精华内容
下载资源
问答
  • 今天遇到了一个需求,需要将多张图片合成一张gif图片,利用搜索引擎搜来搜去,尝试了很多在线的网页端工具,不过要么是有水印,要么是需付费,而且合成效果也不是很好,找来找去,Win10自带的视频合成工具也是不错的...

    今天遇到了一个需求,需要将多张图片合成一张gif图片,利用搜索引擎搜来搜去,尝试了很多在线的网页端工具,不过要么是有水印,要么是需付费,而且合成效果也不是很好,找来找去,Win10自带的视频合成工具也是不错的,不过还是Photoshop功能强大一些。下面介绍一下这两个方法。

    问题索引

    如图,我想将下面12张图片合成一张gif图片。
    在这里插入图片描述

    方法一、使用Win10自带工具(不推荐)

    1.1 选中所有照片,打开照片工具,创建一个新视频

    在这里插入图片描述

    1.2 拖拽图片,选中后可以调整持续时间

    在这里插入图片描述
    在这里插入图片描述

    1.3 预览效果后可以直接导出

    缺点:导出后只能选择格式为mp4,之后利用工具转码为gif即可
    在这里插入图片描述


    方法二、使用Photoshop解决

    2.1 打开Photoshop,点击顶部菜单栏中的【文件】,然后选择【脚本】中的【将文件载入堆栈】

    在这里插入图片描述

    2.2 点击浏览,选择要合成的图片

    注意:导入或许会花费一些些时间,请耐心等待
    在这里插入图片描述

    2.3 导入完成后,点击顶部菜单栏中的【窗口】选择【时间轴】

    在这里插入图片描述

    2.4 在底部时间轴右上角【工具按钮】选择【从图层建立帧】

    在这里插入图片描述
    注意:默认情况下导入后的图层帧是倒序排列的。可采用2.5修改为反向帧。
    在这里插入图片描述

    2.5 全选图片,在底部时间轴右上角【工具按钮】选择【反向帧】

    在这里插入图片描述

    2.6 点击小箭头,调整持续时间(可批量操作)

    在这里插入图片描述

    2.7 选择【文件】中的【存储为Web所用格式…】

    在这里插入图片描述

    2.8 选择【Gif】导出

    在这里插入图片描述

    2.9 效果图

    优点:操作方便,而且导出图片会保持和原图相同,即可以是透明底。之前尝试了很多工具,大多都会将.png图片合成.gif后自动变为白色底,体验较差。
    在这里插入图片描述


    三、未完待续

    当然,后续了解了编程方法,用代码解决,再来补充~~~~

    展开全文
  •  如题,最近工作中遇到一个移动端用户上传照片,然后在线编辑,添加一些别的图片合成的功能,类似于超级简化版美图秀秀。总结了一下,大致操作包含 上传图片,图片压缩、触摸拖动图片、放大/缩小、添加别的图片进行...

    一、序

      如题,最近工作中遇到一个移动端用户上传照片,然后在线编辑,添加一些别的图片合成的功能,类似于超级简化版美图秀秀。总结了一下,大致操作包含 上传图片,图片压缩、触摸拖动图片、放大/缩小、添加别的图片进行合成,最后生成一张新图片。功能比较多,问遍了度娘,也没什么系统的有用信息。蛋疼。。。于是挽起袖子自己撸代码。此过程略痛苦,手机型号不同,兼容性问题比较多。这个我会一一细说。

      额外话,这个demo还涉及到  微信分享,手机验证码,这些代码也没有删,感兴趣的可以看看。

      废话不多说,下面是目录。先看效果图,然后我再简单说说实现过程,把源码贴出来, 有需要的可以去我的 github 下载源码。

     

    二、目录

      1.效果图
      2.原理
      3.问题分析、解决方案
      4.demo下载

     

    1.效果图

     


    2.原理

      图片处理,直接想到 canvas , 这里也是用画布来做的,分析下流程需要上传、编辑、生成新图 这3个步骤。

      a. 上传。 input 文件上传,然后将上传的文件转换为 base64 的格式,这里主要做图片的处理。

      b. 压缩。通过画布将上传的图片进行等比例压缩,图片一般会压缩到100KB左右,具体的看宽高设置,会大、会小。不压缩,无法在线编辑,图片太大了,会卡的要命。

      c. 拖拽。将图片设置为背景图,捕捉 touch 坐标,进行计算,调整图片的横纵坐标。此 demo 电脑手机通用,只需要将 touch 部分的坐标值改成 mouseX,mouseY 或者 clientX、clientY即可。

      d. 图片的裁剪、放大、缩小,旋转。裁剪是根据背景图的坐标,设置画布大小裁剪图片。缩放、旋转,canvas有api,主要做数据的计算。这里这些操作没有采用touch的手势计算。因为我的素材很小,手指操作不方便。所以加的按钮,如果想做手势的逻辑类似,做一下坐标转换即可。

      d. 图片合成。还是canvas的api,添加图片,然后编辑一番,最终保存成base64,传给后台,生成一张图片,本地生成没办法直接使用。所以配合服务端生成最合适。

      e. demo引入了 jQuery ,请使用1.1以上版本的 jQuery ,我用的是 jquery-1.11.3.min.js 。

     


    3.问题分析、解决方案

     现在说一下做这个东西遇到的问题,也说明一下为什么会写这么多代码

      a、canvas 兼容性,IOS8.0 以上,低了貌似都不支持。安卓不太清楚,低级版本肯定是不行了。市面上的手机基本都是OK的。

      b、reader.readAsDataURL(oFile)  手机上传图片,iOS不支持 FileReader 的onload回调,无奈,加了 setTimeout 做延时处理。

      c、手机上传的图片有横屏的,有竖屏的。超级麻烦,导致我们不知道哪个是宽,而且默认展示总不能倒着展示吧。这里引入 exif.js 这个js包可以判断照片的拍摄角度。牛逼啊。拿到拍摄角度之后,我们就可以放到画布里面,再把它旋转,压缩一下。就OK了。

      d、手机的图片太大。现在手机照片动不动就好几MB,画布处理图片是转化成base64计算的,想想吧,一张几兆的图,转换成base64,还得大20%左右,用它编辑,页面一般就卡死了。所以上传成功后,先把图片用画布压缩到100KB以内,这个大小清晰度和处理速度是比较合适的。

      e、压缩图片的时候还有个问题。canvas 的实际大小一定是显示大小的2倍,这样图片才不会是真,否则,你会发现你的图片超级模糊,和马赛克差不多了。

      f、图片移动,这个比较简单了,就是注意移动端、PC端获取到事件对象后,坐标属性名不同,记得别搞错了。

      g、最后图片的生成。canvas 最终生成的是base64,他可以直接保存成图片,不过保存之后我们就取不到了,所以建议发到服务端,服务端生成,返回公网链接。


    4.demo下载

      以上就是整个项目了,有什么问题,可以评论区留言。

      源代码,我会上传到 github ,如果帮到你了,记得给个 star 奥。 下载

     

    核心代码:

    (function (win) {
      var obj = {
        a: 1,
        oldX: "",
        oldY: "",
        ratio: 1,
        ratioBig: 0,
        jsonUrl: 'https://xxxxxxx/api/xxxx',
        radioSmall: 0,
        num: 1,
        setWidth: 432,    //图片需要压缩到的尺寸   216,135
        theDataBase: "",
        yaSuoBase64: "",
        hcBase64: "",
        image: new Image(),    //放到画布的img
        bookCode: 12221212,
        flag: true,
        bodyWidth: '',
        bodyHeight: '',
        ifImgUpload: false,
        base64Zong: "",
        imgNewName: "",
    //首页的js。横竖屏、微信分享、滑动跳转
        page1Init: function () {
          var w = this;
          if ($(win).width() >= $(win).height()) {
            w.bodyWidth = parseInt($(window).height()) + 64;
            w.bodyHeight = $(window).width();
            $('body,html').width(w.bodyWidth);
            $('body,html').height(w.bodyHeight);
          } else {
            w.bodyWidth = $(window).width();
            w.bodyHeight = $(window).height();
            $('body,html').width(w.bodyWidth);
            $('body,html').height(w.bodyHeight);
          }
    
          window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
            if (window.orientation === 180 || window.orientation === 0) {
              $('body,html').width(bodyWidth);
              $('body,html').height(bodyHeight);
            }
            if (window.orientation === 90 || window.orientation === -90) {
              $('body,html').width(bodyWidth);
              $('body,html').height(bodyHeight);
            }
          }, false);
    
          // 初始化微信分享的
          // w.wxConfig();
          // w.wxReady();
    
          var oldX = 0, oldY = 0;
          $("body").on("touchstart", imgTouchStart);
          $("body").on("touchmove", imgTouchMove);
    
          //手指按下时,捕捉事件,取坐标值,设置参数
          function imgTouchStart(e) {
            //阻止事件冒泡的
            e.stopImmediatePropagation();
            oldX = e.originalEvent.touches[0].clientX;
            oldY = e.originalEvent.touches[0].clientY;
          }
    
          function imgTouchMove(e) {
            e.stopImmediatePropagation();
            var x = e.originalEvent.touches[0].clientX - oldX;
            var y = e.originalEvent.touches[0].clientY - oldY;
            if (y < -150) {
              window.location.href = 'getBooks.html?';
            }
          }
        },
    
    //上传照片页的js。横竖屏、微信分享、上传照片
        page2Init: function () {
          var w = this;
          if ($(win).width() >= $(win).height()) {
            w.bodyWidth = parseInt($(window).height()) + 64;
            w.bodyHeight = $(window).width();
            $('body,html').width(w.bodyWidth);
            $('body,html').height(w.bodyHeight);
          } else {
            w.bodyWidth = $(window).width();
            w.bodyHeight = $(window).height();
            $('body,html').width(w.bodyWidth);
            $('body,html').height(w.bodyHeight);
          }
    
          window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
            if (window.orientation === 180 || window.orientation === 0) {
              $('body,html').width(bodyWidth);
              $('body,html').height(bodyHeight);
            }
            if (window.orientation === 90 || window.orientation === -90) {
              $('body,html').width(bodyWidth);
              $('body,html').height(bodyHeight);
            }
          }, false);
    
          // w.wxConfig();
          // w.wxReady3();
    
          //上传图片进行处理
          w.uploadImg();
    
          if (localStorage.getItem("imgFlag") == "true") {
            $(".f-scInLock").hide();
          }
    
          //选好照片,准备制作
          $('.m-loadBtn').on("tap", function () {
            $('.m-loadBtn').css({"color": "#C64100"});
            setTimeout(function () {
              $('.m-loadBtn').css({"color": "white"});
            }, 300);
            if (w.ifImgUpload == true) {
              $('.g-wrap2').hide();
              $('.g-wrap3').show();
              $("#m-loadImg").attr("src", w.yaSuoBase64);
            } else {
              $('.j-pop p').text("还没有选择喜欢照片吆!");
              $('.j-pop').show();
              setTimeout(function () {
                $('.j-pop').hide();
              }, 1500);
            }
          });
    
          $(".m-step1 .f-scIn1").on("tap", function () {
            $(".m-sucaiOut").show();
            $(".m-sucaiOut").css({"width": "70px", "opacity": "1"});
            $(".m-imgBox .f-sucai").attr("src", "img/sucai1.png");
          });
          $(".m-step1 .f-scIn2").on("tap", function () {
            $(".m-sucaiOut").show();
            $(".m-sucaiOut").css({"width": "70px", "opacity": "1"});
            $(".m-imgBox .f-sucai").attr("src", "img/sucai2.png");
          });
          $(".m-step1 .f-scIn3").on("tap", function () {
            var sucai3 = localStorage.getItem("imgFlag");
            if (sucai3 == "true") {
              $(".m-sucaiOut").show();
              $(".m-sucaiOut").css({"width": "70px", "opacity": "1"});
              $(".m-imgBox .f-sucai").attr("src", "img/sucai3.png");
            } else {
              $('.j-pop p').text("分享后可解锁吆!");
              $('.j-pop').show();
              setTimeout(function () {
                $('.j-pop').hide();
              }, 1500);
            }
          })
          $(".f-sucaiDelete").on("tap", function () {
            $(".m-sucaiOut").css({"width": "1px", "opacity": "0", "top": "4px", "left": "100px"});
            $(".m-imgBox .f-sucai").attr("src", "img/wu.png");
          });
    
    
          $(".m-step2 .f-scIn1").on("tap", function () {
            $(".imgKuang .imgK").attr("src", "img/sucai4.png");
          });
          $(".m-step2 .f-scIn2").on("tap", function () {
            $(".imgKuang .imgK").attr("src", "img/sucai5.png");
          });
    
    
          $(".m-makeBtn").on("tap", function () {
            $("#loadingSection").show();
            setTimeout(function () {
              $("#loadingSection").hide();
            }, 1800);
    
            w.imageMake();
          });
    
          $(".m-getBtn").on("tap", function () {
            $(".m-login").show();
            $(".m-mengBan").show();
          });
          $(".m-closeLogin").on("tap", function () {
            $(".m-login").hide();
            $(".m-mengBan").hide();
          });
    
          $(".wx-share").on("tap", function () {
            $(".wx-share").hide();
            $(".m-mengBan").hide();
          });
    
          $(".m-oldManBtn").on("tap", function () {
            $(".wx-share").show();
            $(".m-mengBan").show();
            w.sendImgSouce();
            w.wxReady2();
          });
    
          w.initEvent();
        },
    
    
        resize: function () {},
    
        wxConfig: function () {
          var w = this;
          var jsapi_ticket, nonceStr, signature, timestamp, getCode;
          var url = 'http://xxxxxxx/'; //正式库
          //获取config配置
          var Url = window.location.href;
          $.ajax({
            type: 'get',
            url: 'http:/xxxxxxx',
            data: {
              weixinurl: Url
            },
            timeout: 10000, //10秒超时
            callbackParameter: 'callback',
            async: false,
            jsonp: "jsonpcallback",
            success: function (o) {
              jsapi_ticket = o.jsapi_ticket;
              nonceStr = o.nonceStr;
              signature = o.signature;
              timestamp = o.timestamp;
            }
          });
          wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: 'xxxxxxxxx', // 必填,公众号的唯一标识
            timestamp: timestamp, // 必填,生成签名的时间戳
            nonceStr: nonceStr, // 必填,生成签名的随机串
            signature: signature, // 必填,签名,见附录1
            jsApiList: [
              'checkJsApi',
              'onMenuShareTimeline',
              'onMenuShareAppMessage',
              'onMenuShareQQ',
              'onMenuShareWeibo',
              'onMenuShareQZone',
              'hideMenuItems',
              'showMenuItems',
              'hideAllNonBaseMenuItem',
              'showAllNonBaseMenuItem',
              'translateVoice',
              'startRecord',
              'stopRecord',
              'onVoiceRecordEnd',
              'playVoice',
              'onVoicePlayEnd',
              'pauseVoice',
              'stopVoice',
              'uploadVoice',
              'downloadVoice',
              'chooseImage',
              'previewImage',
              'uploadImage',
              'downloadImage',
              'getNetworkType',
              'openLocation',
              'getLocation',
              'hideOptionMenu',
              'showOptionMenu',
              'closeWindow',
              'scanQRCode',
              'chooseWXPay',
              'openProductSpecificView',
              'addCard',
              'chooseCard',
              'openCard'
            ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
          });
        },
        wxReady: function () {
          wx.ready(function () {
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxxxxxx/index.html', // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxxxx/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
              },
              cancel: function (res) {
              }
            });
            //alert('已注册获取“发送给朋友圈”状态事件');
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxxxx/index.html', // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxxxx/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
              },
              cancel: function (res) {
              }
            });
          });
        },
        wxReady3: function () {
          wx.ready(function () {
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxxx/index.html', // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxxxxxx/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
                $(".f-scInLock").hide();
                $(".f-scInLock").css({"width": "0px", "height": "0px", "display": "none"});
              },
              cancel: function (res) {
              }
            });
            //alert('已注册获取“发送给朋友圈”状态事件');
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxxxx/index.html', // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxxxx/img/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
                $(".f-scInLock").hide();
                $(".f-scInLock").css({"width": "0px", "height": "0px", "display": "none"});
              },
              cancel: function (res) {
              }
            });
          });
        },
        wxReady2: function () {
          var w = this;
          wx.ready(function () {
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxxxx/sharePage.html?imgName=' + w.imgNewName, // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxx/img/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
                $(".wx-share").hide();
                $(".m-mengBan").hide();
                $(".f-scInLock").hide();
                $(".f-scInLock").css({"width": "0px", "height": "0px", "display": "none"});
              },
              cancel: function (res) {
              }
            });
            //alert('已注册获取“发送给朋友圈”状态事件');
            wx.onMenuShareAppMessage({
              title: '嘿,我愿意做你的圣诞老人!', // 分享标题
              link: 'http://xxxxx/sharePage.html?imgName=' + w.imgNewName, // 分享链接
              desc: '叮叮当,叮叮当,今年你愿意做我的圣诞老人吗……',
              imgUrl: 'http://xxxxxx/img/wxbanner.png', // 分享图标
              trigger: function (res) {
              },
              success: function (res) {
                localStorage.setItem("imgFlag", "true");
                $(".wx-share").hide();
                $(".m-mengBan").hide();
                $(".f-scInLock").hide();
                $(".f-scInLock").css({"width": "0px", "height": "0px", "display": "none"});
              },
              cancel: function (res) {
              }
            });
          });
        },
    
    
        //照片上传函数
        uploadImg: function () {
          var w = this;
          var loadFile = document.getElementById("file");
          loadFile.addEventListener("change", function () {
            $(".m-thewen33").hide();
            $(".m-thewen").show();
    
            $(".f-theImg").css({"width": "100%"});
            w.ifImgUpload = true;
    
            $("#loadingSection").show();
            setTimeout(function () {
              $("#loadingSection").hide();
            }, 2700);
    
            var oFile = loadFile.files[0];
            console.log(oFile);
            if (!new RegExp("(jpg|jpeg|png)+", "gi").test(oFile.type)) {
              alert("照片上传:文件类型必须是JPG、JPEG、PNG");
              return;
            }
            //新建一个文件对象
            var reader = new FileReader();
            //读出这个文件的 base64 的数据流,这个函数是专门转base64的,不加他,下面没法用base64
            reader.readAsDataURL(oFile);
    
            //因为  iOS 不支持 FileReader 的onload回调,所以,这里只能加延迟处理了
            setTimeout(function () {
              //先取照片的拍摄方向角
              EXIF.getData(oFile, function () {
                EXIF.getAllTags(this);
                var zzz = EXIF.getTag(this, 'Orientation');
                var spanData = document.getElementsByClassName("tspanme");
                if (zzz == 1 || zzz == undefined) {
                  spanData[0].innerText = 0;
    //                            alert("0度");
    //                            console.log("0度");
                } else if (zzz == 6) {
                  spanData[0].innerText = 90;
    //                            alert("90度");
    //                            console.log("90度");
                } else if (zzz == 8) {
                  spanData[0].innerText = 270;
    //                            alert("270度");
    //                            console.log("270度");
                } else if (zzz == 3) {
                  spanData[0].innerText = 180;
    //                            alert("180度");
    //                            console.log("180度");
                }
              });
    
    
              var img = new Image();
              img.src = reader.result;
              //根据拍摄角度不同,把图片旋转适当角度,纠正图片
              //除了修改方向,不做其他任何修改
              setTimeout(function () {
                var spanData = document.getElementsByClassName("tspanme");
                var theText = spanData[0].innerText;
    
                console.log("这个保存的角度" + theText);
                var canvas = document.createElement("canvas");
                var cantent = canvas.getContext("2d");
                var width = img.naturalWidth,
                  height = img.naturalHeight;
    
                if (theText == 0) { //0
                  canvas.width = width;
                  canvas.height = height;
                  cantent.drawImage(img, 0, 0, width, height, 0, 0, width, height);
                  console.log("0");
                } else if (theText == 90) {
                  canvas.width = height;
                  canvas.height = width;
                  cantent.save();
                  cantent.rotate(90 * Math.PI / 180);
                  cantent.drawImage(img, 0, -height);
                  cantent.restore();
                  console.log("90");
                } else if (theText == 180) {
                  canvas.width = width;
                  canvas.height = height;
                  cantent.save();
                  cantent.rotate(180 * Math.PI / 180);
                  cantent.drawImage(img, -width, -height);
                  cantent.restore();
                  console.log("180");
                } else if (theText == 270) {
                  canvas.width = height;
                  canvas.height = width;
                  cantent.save();
                  cantent.rotate(270 * Math.PI / 180);
                  cantent.drawImage(img, -width, 0);
                  cantent.restore();
                  console.log("270");
                }
                w.theDataBase = canvas.toDataURL();
                setTimeout(function () {
                  w.yaSuoImg();
                }, 200);
              }, 300);
            }, 400);
          })
        },
    
    
        //处理图片的函数
        imageMake: function () {
          var w = this,
            theAngle = 0,
            imgHat = document.getElementsByClassName("f-sucai")[0];
    
          theAngle = getEletAngle();
          console.log("当前素材的角度:" + theAngle);
    
          var canvasHat = document.createElement("canvas"),
            cantentHat = canvasHat.getContext("2d"),
            widthHat = imgHat.naturalWidth,
            heightHat = imgHat.naturalWidth;
    
          console.log(widthHat);
          console.log(heightHat);
          console.log(theAngle);
          canvasHat.width = widthHat;
          canvasHat.height = heightHat;
          cantentHat.save();
          cantentHat.translate(widthHat / 2, heightHat / 2);
          cantentHat.rotate(theAngle * Math.PI / 180);
          cantentHat.translate(-widthHat / 2, -heightHat / 2);
          cantentHat.drawImage(imgHat, 0, 0);
          cantentHat.restore();
    
          imgHat.src = canvasHat.toDataURL();
    
          setTimeout(function () {
            var img1 = document.getElementById("m-loadImg"),
              width = img1.naturalWidth,
              height = img1.naturalHeight,
              canvas = document.createElement("canvas"),
              cantent = canvas.getContext("2d"),
              oldTop = $("#m-loadImg")[0].offsetTop,
              oldLeft = $("#m-loadImg")[0].offsetLeft,
              imgK = document.getElementsByClassName("imgK")[0],
              imgKuangOut = document.getElementsByClassName("imgKuang")[0],
              imgSuCai = document.getElementsByClassName("f-sucai")[0],
              imgSuCaiOut = document.getElementsByClassName("m-sucaiOut")[0],
    
              //缩放之后图片的宽度
              scWidth = imgSuCai.width,
              scHeight = imgSuCai.height,
    
              scOffsetTop = imgSuCaiOut.offsetTop,
              scOffsetLeft = imgSuCaiOut.offsetLeft;
    
            // console.log("------------------------");
            // console.log(imgSuCai);
            // console.log(imgSuCaiOut);
            // console.log(scWidth);
            // console.log(scHeight);
            // console.log(scOffsetTop);
            // console.log(scOffsetLeft);
    
            canvas.width = 270;
            canvas.height = 194;
    
            // console.log("原大小:");
            // console.log(img1.naturalWidth);
            // console.log(img1.naturalHeight);
            // console.log(imgK.naturalWidth);
            // console.log(imgK.naturalHeight);
    
    
            // console.log("相框的上定位" + imgK.offsetTop);
            // console.log("相框的下定位" + imgK.offsetLeft);
            //
            // console.log("插入素材的数据:");
            // console.log(scWidth);
            // console.log(scHeight);
            // console.log(scOffsetTop);
            // console.log(scOffsetLeft);
    
    
            var yasuobi = width / 270;
            // console.log("压缩之后的宽度" + width);
            // console.log("position的上定位" + oldTop);
            // console.log("position的左定位" + oldLeft);
    
    //                alert(-oldLeft*yasuobi+"水平位移");
    //                alert(-oldTop*yasuobi+"垂直位移");
    
    
            setTimeout(function () {
              //画上照片
              cantent.drawImage(img1, 0, 0, width, height, oldLeft, oldTop, 270, height / yasuobi);
              //画上素材
              cantent.drawImage(imgSuCai, 0, 0, imgSuCai.naturalWidth, imgSuCai.naturalHeight, scOffsetLeft, scOffsetTop, scWidth, scHeight);
              //画上相框
              cantent.drawImage(imgK, 0, 0, imgK.naturalWidth, imgK.naturalHeight, imgKuangOut.offsetLeft, imgKuangOut.offsetTop, imgK.width, imgK.height);
              w.hcBase64 = canvas.toDataURL();
    
    
              //做最终的合成
              var imgZong = new Image();
              imgZong.src = w.hcBase64;
    
              setTimeout(function () {
                var canvas111 = document.createElement("canvas"),
                  cantent111 = canvas111.getContext("2d"),
                  imgKuangTrue = document.getElementById("g-kuangTrue"),
                  theEWM = document.getElementById("g-ewm");
    
                canvas.width = 326.5;
                canvas.height = 335;
    
                cantent.drawImage(imgKuangTrue, 0, 0, imgKuangTrue.naturalWidth, imgKuangTrue.naturalHeight, 0, 0, 326.5, 335);
                cantent.drawImage(imgZong, 0, 0, imgZong.naturalWidth, imgZong.naturalHeight, 28, 47, 270, 194);
                cantent.drawImage(theEWM, 0, 0, theEWM.naturalWidth, theEWM.naturalHeight, 236, 249, 64, 64);
                w.base64Zong = canvas.toDataURL();
                setTimeout(function () {
                  $(".g-wrap3").hide();
                  $(".g-wrap4").show();
                  $(".f-shuchu").attr("src", w.base64Zong);
                }, 400)
              }, 500)
              // console.log("合成的图片");
              //console.log(w.theDataBase.length/1024+"KB");
            }, 400)
    
          }, 700)
        },
    
    
        //压缩函数
        yaSuoImg: function () {
          var w = this;
          yaWidth = w.setWidth / 2,    //  yaWidth  这个是实际照片一半的大小,通过设置它实现压缩
            canvas = document.createElement("canvas"),
            cantent = canvas.getContext("2d"),
            img = new Image();
          img.src = w.theDataBase;
          //这个iOS是支持的,iOS不支持的是file对象的onload函数
          img.onload = function () {
            var width = img.naturalWidth,
              height = img.naturalHeight,
              //图片的压缩比
              theRadio = img.naturalWidth / yaWidth;
            //如果图片尺寸小于设定画布的尺寸,不压缩,输出原图
            if (theRadio <= 1) {
              theRadio = 1;
              canvas.width = img.naturalWidth;
              canvas.height = img.naturalHeight;
              canvas.style.width = img.naturalWidth / 2 + "px";
              canvas.style.height = img.naturalHeight / 2 + "px";
              cantent.drawImage(img, 0, 0, width, height, 0, 0, width, height);
            } else {
              //为了避免失真,canvas实际大小设置为显示大小的2倍
              canvas.width = yaWidth * 2;
              canvas.height = (height / theRadio) * 2;
              canvas.style.width = yaWidth + "px";
              canvas.style.height = height / theRadio + "px";
              //注意,图片要取实际大小裁剪,但是显示大小选择和canvas同样的大小,这样显示的不失真、小,但实际的大。不失真
              cantent.drawImage(img, 0, 0, width, height, 0, 0, yaWidth * 2, height / theRadio * 2);
              console.log("压缩之后的图片大小,宽:  " + yaWidth * 2 + "高:  " + height / theRadio * 2);
            }
    
            // console.log("************************");
            // console.log(theRadio);
            // console.log(width);
            // console.log(height);
            // console.log(yaWidth * 2);
            // console.log((height / theRadio) * 2);
            w.yaSuoBase64 = canvas.toDataURL();
            setTimeout(function () {
              $(".g-wrap2 .f-theImg").attr("src", w.yaSuoBase64);
              // console.log("压缩之后大小");
              // console.log(w.yaSuoBase64.length / 1024 + "KB");
    //                    alert("压缩之后大小:"+w.yaSuoBase64.length/1024+"KB");
            }, 200)
          };
        },
    
    
        initEvent: function () {
          var w = this;
          $('.getCode').on('tap', function () {
            $('.m-phone').blur();
            $('.m-code').blur();
            var phoneNum = $('.m-phone').val();
            if (phoneNum == '') {
              $('.j-pop').fadeIn();
              $('.j-pop p').text('手机号不能为空');
              setTimeout(function () {
                $('.j-pop').fadeOut();
              }, 2000);
              return false;
            } else if (!/^1[3|4|5|7|8][0-9]{9}$/.test(phoneNum)) {
              $('.j-pop').fadeIn();
              $('.j-pop p').text('手机号格式不正确');
              setTimeout(function () {
                $('.j-pop').fadeOut();
              }, 2000);
              return false;
            }
            if (w.flag == true) {
              w.codeAjax();
              var time = 60;
              $('.getCode').attr("disabled", "disabled");
              w.flag = false;
              var t = setInterval(function () {
                time--;
                $('.getCode').text(time + "s后再发送");
                $('.getCode').css("background", '#EFEFEF');
                $('.getCode').css("color", 'gray');
                if (time == 0) {
                  $('.getCode').removeAttr('disabled');
                  clearInterval(t);
                  $('.getCode').text("获取验证码");
                  w.flag = true;
                  $('.getCode').css("color", '#CB402F');
                }
              }, 1000);
            }
          });
          $('.m-getBook').on('tap', function () {
            var codeTxt = $('.m-code').val();
            var phoneNum = $('.m-phone').val();
            if (phoneNum == '') {
              $('.j-pop').fadeIn();
              $('.j-pop p').text('手机号不能为空');
              setTimeout(function () {
                $('.j-pop').fadeOut();
              }, 2000);
            } else if (codeTxt == '') {
              $('.j-pop').fadeIn();
              $('.j-pop p').text('验证码不能为空');
              setTimeout(function () {
                $('.j-pop').fadeOut();
              }, 2000);
              return false;
            } else if (/^1[3|4|5|7|8][0-9]{9}$/.test(phoneNum) && codeTxt != "") {
              $.ajax({
                type: 'post',
                url: w.jsonUrl,
                data: "method=xxxx" + "&content=" + JSON.stringify({
                  customerName: phoneNum,
                  sendBookActivityCode: w.bookCode,
                  checkCode: codeTxt
                }),
                callbackParameter: 'callback',
                async: true,
                jsonp: "jsonpcallback",
                success: function (o) {
                  if (o.status == 1) {
                    $('.j-pop').fadeIn();
                    $('.j-pop p').text('领取成功!');
                    setTimeout(function () {
                      $('.j-pop').fadeOut();
                      window.location.href = "http://xxxxx";
                    }, 800);
                  } else if (o.status == 2) {
                    $('.j-pop').fadeIn();
                    $('.j-pop p').text("您已领取过该书籍");
                    setTimeout(function () {
                      $('.j-pop').fadeOut();
                      window.location.href = "http://xxxx";
                    }, 2000);
                  }
                }
              });
    
            } else if (!/^1[3|4|5|7|8][0-9]{9}$/.test(phoneNum)) {
              $('.j-pop').fadeIn();
              $('.j-pop p').text('手机号错误');
              setTimeout(function () {
                $('.j-pop').fadeOut();
              }, 2000);
            }
          });
        },
    
        codeAjax: function () {
          var w = this;
          var phoneNum = $('.m-phone').val();
          if (/^1[3|4|5|6|7|8][0-9]{9}$/.test(phoneNum)) {
            $.ajax({
              type: 'post',
              url: w.jsonUrl,
              timeout: 2000, //10秒超时
              data: "method=xxxx" + "&content=" + JSON.stringify({
                mobileNum: phoneNum,
                type: 'LOGIN_CHECK'
              }),
              callbackParameter: 'callback',
              async: false,
              jsonp: "jsonpcallback",
              success: function (o) {
                if (o.status == 1) {
                  $('.j-pop').fadeIn();
                  $('.j-pop p').text('短信发送成功');
                  setTimeout(function () {
                    $('.j-pop').fadeOut();
                  }, 2000);
                } else if (o.status == 0) {
                  if (o.code == "10002006") {
                    $('.j-pop').fadeIn();
                    $('.j-pop p').text('请求过于频繁,一分钟只能请求一次');
                    setTimeout(function () {
                      $('.j-pop').fadeOut();
                    }, 2000);
                  } else if (o.code == "10002003") {
                    $('.j-pop').fadeIn();
                    $('.j-pop p').text('短信发送失败');
                    setTimeout(function () {
                      $('.j-pop').fadeOut();
                    }, 2000);
                  }
                }
              }
            });
          } else {
            $('.j-pop').fadeIn();
            $('.j-pop p').text('手机号格式不正确');
            setTimeout(function () {
              $('.j-pop').fadeOut();
            }, 2000);
          }
        },
    
        //上传做好的图片,并获取后台生成的图片路径
        sendImgSouce: function () {
          var w = this;
          console.log("开始上传");
          $.ajax({
            type: 'post',
            url: 'http://xxxxxxx/upload/activityBase64',
            data: {
              pictureStream: w.hcBase64,
              activityId: "1508342400"
            },
            timeout: 10000, //10秒超时
            callbackParameter: 'callback',
            async: false,
            jsonp: "jsonpcallback",
            success: function (o) {
              console.log("回调");
              console.log(o);
              var b = o.data.split("?");
              var c = b[0].split("event/");
              w.imgNewName = c[1];
              console.log(w.imgNewName);
            }
          });
          console.log("上传成功");
        }
    
      }
      win.page = obj;
    })(window)
    //图片操作获取具体数据的函数
    function imageMaker(eleID,otherID){
        var oldX=0,
            oldY=0,
            ratio=1;
            
        $(""+eleID+"").on("touchstart",imgTouchStart);
        $(""+eleID+"").on("touchmove",imgTouchMove);
        $(""+eleID+"").on("touchend",imgTouchEnd);
        
        //手指按下时,捕捉事件,取坐标值,设置参数
        function imgTouchStart(e){
            //阻止事件冒泡的
            e.stopImmediatePropagation();
            e.preventDefault(); 
            $(""+eleID+"").attr("draggable",true);
    
            oldX = e.originalEvent.touches[0].clientX;
            oldY = e.originalEvent.touches[0].clientY;
        }
            
        function imgTouchMove(e){
            e.stopImmediatePropagation();
            //阻止事件冒泡,避免,移动照片时,整个页面也会随滚动条移动
            e.preventDefault();
            if($(""+eleID+"").attr("draggable")) {
                var x = e.originalEvent.touches[0].clientX - oldX;
                var y = e.originalEvent.touches[0].clientY - oldY;
                var oldTop = $(""+eleID+"")[0].offsetTop;
                var oldLeft = $(""+eleID+"")[0].offsetLeft;
                var NewTop = y + parseInt(oldTop);
                var newLeft = x + parseInt(oldLeft);
                $(""+eleID+"").css({"top":NewTop+"px","left":newLeft+"px"});
                oldX = e.originalEvent.touches[0].clientX;
                oldY = e.originalEvent.touches[0].clientY;
            }
        }
        
        //手指拿开时,设置参数
        function imgTouchEnd(e) {
            e.stopImmediatePropagation();
            e.preventDefault();
            $(""+eleID+"").attr("draggable",false);
        }
        
        
        $(".shape1").on("touchstart",function(e){
            setImgSmall();
        });
        
        $(".shape3").on("touchstart",function(e){
            setImgBig();
        });
        
        $(".shape2").on("touchstart",function(e){
            setImgAngle();
        });
        
        //放大、缩小的
        function setImgBig() {
            var width = parseInt($(""+otherID+"").width()) * 1.03;
            var height = parseInt($(""+otherID+"").height()) * 1.03;
    
            $(""+otherID+"").css({
                'width': width+"px",
                'height': height+"px",
            });
            console.log("打印我"+width);
        }
        
        function setImgSmall() {
            var width = parseInt($(""+otherID+"").width()) * 0.97;
            var height = parseInt($(""+otherID+"").height()) * 0.97;
    
            $(""+otherID+"").css({
                'width': width+"px",
                'height': height+"px",
            });
        }
        
        function setImgAngle(){
            //这里只取图片的角度,值旋转图片。外框不做操作了
            var theAngle = getEletAngle();
            var angleNow = theAngle+10;
            $(".f-sucai").css({'transform': "rotate("+angleNow+"deg)"});
        }
    }
    
    
    //获取元素旋转角度
        function getEletAngle(eletClass){
            var el = document.getElementsByClassName("f-sucai")[0];
            console.log(el);
            var st = window.getComputedStyle(el, null);
            var tr = st.getPropertyValue("-webkit-transform") ||
                st.getPropertyValue("-moz-transform") ||
                st.getPropertyValue("-ms-transform") ||
                st.getPropertyValue("-o-transform") ||
                st.getPropertyValue("transform") ||
                "FAIL";
            //console.log('Matrix: ' + tr);
            var values = tr.split('(')[1].split(')')[0].split(',');
            var a = values[0];
            var b = values[1];
            var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
            //console.log('Rotate: ' + angle + 'deg');
            return angle;
        }

     

    转载于:https://www.cnblogs.com/pengfei-nie/p/7725005.html

    展开全文
  • 但并非一定需要多张照片才能使用Photomatix。色调映射工具(Tone Mapping tool)也能用于48位TIFF文件,同样适用于48位压缩工具(Compression tool)。另一技巧是使用从RAW文件解压出来的不同曝光度的照片。这对于...
  • 示例4 喷溅合成 用一组照片完成一段动感的相册,如果只是...新建合成,导入多张墨滴的图片素材,导入多张照片素材,选择一张你喜欢的背景图片做完整个相册的背景 每次导入素材,注意调整大小,匹配合成的高度宽度...

    示例4 喷溅合成

    用一组照片完成一段动感的相册,如果只是使用常规的转场特效,难免会缺乏新意,若使用墨滴图案作为蒙版来实现图片之间的过渡,则产生一种传统或者怀旧的感觉。

    而且这只是一种方法,你可以选择更换不同的素材,来进行制作,不一定局限在水墨,古风

    新建合成,导入多张墨滴的图片素材,导入多张照片素材,选择一张你喜欢的背景图片做完整个相册的背景

    每次导入素材,注意调整大小,匹配合成的高度宽度

    拖动墨滴图片至顶层,调整缩放参数,拖入照片至时间线,选择蒙版模式为  亮度反转,效果如下图

    选择顶层墨滴的图层,右键 预合成 移动全部属性

    双击打开预合成,新建一个白色纯色层于底层 一定要铺满屏幕,否则你就会看到墨滴的边框,如下图所示

    如果觉得墨滴的蒙版效果不是很好,可以选择墨滴图层,添加 效果 颜色校正 色阶 降低亮度,增加对比度

    为背景图片添加 三色调 效果控件,我之前提到过这个效果,可以根据需要改变画面颜色

    选中墨滴图层,激活缩放 属性 添加关键帧,具体数值根据自己情况进行调整  切换至 合成1 播放查看效果

    按照第一张图片的方式继续添加第二张

    对于图片的处理有一些技巧

    剪裁图片 :选中矩形工具,圈中需要的部分,建立新的蒙版即可

    旋转,缩放图片:图层  变换   这里可以改变图片的锚点(锚点即图片的中心,一切操作都是以它为中心旋转,缩放)

    淡出动画,改变图片的不透明度 建立关键帧 进行播放

    对于不同的墨滴,可以根据示例2云彩的变化来改变墨滴的形状,可以进行旋转,缩放等操作,这些都是个人喜好

    最后保存文件,点击播放即可

    展开全文
  • matlab实现图像拼接

    2020-08-17 16:41:42
    根据特征点的相互匹配,可以将张小视角的图像拼接成为一张大视角的图像,在广角照片合成、卫星照片处理、医学图像处理等领域都有应用。早期的图像拼接主要是运用像素值匹配的方法。后来,人们分别在两幅图像中寻找...
  • 放假归来,下午下了个把包围曝光拍摄的多张照片合成一张层次比较明显的一张图片的一个Nuke Op(本来想写的是Focus Bracketing的但发现效果不是很好),用的最简单的方法既亮度越接近0.5其权值越,和专业的混合...

    放假归来,下午下了个把包围曝光拍摄的多张照片合成出一张层次比较明显的一张图片的一个Nuke Op(本来想写的是Focus Bracketing的但发现效果不是很好),用的最简单的方法既亮度越接近0.5其权值越大,和专业的混合软件比差距还是比较大的……哭



    输入

    来自wiki,虽然是缩略图但也可以看到,因为光比太大,左边的图能看清亮出细节但看天空漆黑,与之相反的最右边的图能看清天空时整个建筑都爆掉了。



    界面

    右边的两个transform是为了对齐。


    输出

    如图,同一张图片能看清楚云彩和建筑最明亮的地方的细节。效果一般,但就这么滴了。


    把源码发上来吧~ 

    // by cuckon
    #pragma warning(disable:4312)
    #include "DDImage/Iop.h"
    #include "DDImage/Row.h"
    #include "DDImage/Tile.h"
    #include "DDImage/Knobs.h"
    #include <vector>
    
    using namespace DD::Image;
    using namespace std;
    
    #define For(i,from,to) for (int i = from;i<to;i++)
    #define ForI(to) For(i,0,to)
    
    static const char* const CLASS = "BracketStacker";
    static const char* const HELP = "Use to composite brackted images. ";
    typedef vector<Row*> RowList;
    
    const char *const kOperationLabel[] = {
    	"HDRI",
    	"Defocus",
    	NULL
    };
    
    enum Operation {
    	kHDRI = 0,
    	kDefocus
    };
    
    float RGB2Lum(float r,float g, float b) {
    	return 0.2125f * r + 0.7154f * g + 0.0721f * b;
    }
    
    float weightCurve(float dark,float light,float input){
    	input = MIN(1.0f,MAX(input,0.0f));
    	return pow(input,light)  *  pow((1-input),dark);
    }
    
    class BracketStacker : public Iop
    {
    	// These are the locations the user interface will store into:
    	int		operation;
    	double	dark_weight, light_weight,pre_gamma;
    public:
    	BracketStacker(Node*);
    	void _validate(bool);
    	void _request(int, int, int, int, ChannelMask, int);
    	void engine(int y, int x, int r, ChannelMask, Row &);
    	virtual void knobs(Knob_Callback);
    	const char* Class() const { return CLASS; }
    	const char* node_help() const { return HELP; }
    	static const Description d;
    
    	int minimum_inputs()const{return 2;}
    	int maximum_inputs()const{return 99999;}
    
    };
    
    BracketStacker::BracketStacker(Node* node) : Iop(node)
    {
    	operation = 0;
    	dark_weight = 1;
    	light_weight = 1;
    	pre_gamma = 1;
    }
    
    void BracketStacker::knobs(Knob_Callback f)
    {
    	Float_knob(f,&dark_weight,IRange(0,100),"dark","dark");
    	Float_knob(f,&light_weight,IRange(0,100),"light","light");
    	Float_knob(f,&pre_gamma,IRange(0,100),"pre_gamma","pre_gamma");
    }
    
    static Iop* Blocky_c(Node* node) { return new BracketStacker(node); }
    const Iop::Description BracketStacker::d(CLASS, "Cuckon/BracketStacker", Blocky_c);
    
    
    void BracketStacker::_validate(bool for_real)
    {
    	// Get the size and other information from the input image:
    	copy_info();
    	Iop::validate(for_real);
    }
    
    void BracketStacker::_request(int x, int y, int r, int t, ChannelMask channels, int count)
    {
    	for(int i = 0;i<inputs();i++){
    		input(i)->request(x, y, r, t, channels, count);
    	}
    }
    
    void BracketStacker::engine(int y, int l, int r, ChannelMask channels, Row& out)
    {
    	if (!channels.contains(Mask_RGB))
    		return;
    	float	*weight = new float[inputs()],
    			*lum = new float[inputs()],
    			current_lum_sum;
    	Row::WritablePtr	ptr_r = out.writable(Chan_Red),
    						ptr_g = out.writable(Chan_Green),
    						ptr_b = out.writable(Chan_Blue);
    	
    	// prepare all rows for calc
     	RowList				input_rows;
     	ForI(inputs()) {
     		input_rows.push_back(new Row(l,r));
     		input_rows.back()->get(*input(i),y,l,r,channels);
     	}
    
    	// adjust each pixel
    	for (int x = l;x<r;x++)
    	{
    		current_lum_sum = 0;
    		ForI(inputs()) {
     			lum[i] = RGB2Lum((*input_rows[i])[Chan_Red][x],
     							(*input_rows[i])[Chan_Green][x],
     							(*input_rows[i])[Chan_Blue][x]
    			);
    			lum[i] = weightCurve((float)dark_weight,(float)light_weight,pow(lum[i],(float)pre_gamma));
    			current_lum_sum += lum[i];
    		}
    		ForI(inputs())
    			weight[i] = lum[i]/current_lum_sum;
    		
    		ptr_r[x] = ptr_g[x] = ptr_b[x] = 0;
    		ForI(inputs()){
    			ptr_r[x]+= weight[i]*(*input_rows[i])[Chan_Red][x];
    			ptr_g[x]+= weight[i]*(*input_rows[i])[Chan_Green][x];
    			ptr_b[x]+= weight[i]*(*input_rows[i])[Chan_Blue][x];
    		}
    	}
    }
    


    展开全文
  • 图像拼接之MATLAB实现

    万次阅读 多人点赞 2017-05-18 11:09:46
    根据特征点的相互匹配,可以将张小视角的图像拼接成为一张大视角的图像,在广角照片合成、卫星照片处理、医学图像处理等领域都有应用。早期的图像拼接主要是运用像素值匹配的方法。后来,人们分别在两幅图像中寻找...
  • 根据特征点的相互匹配,可以将张小视角的图像拼接成为一张大视角的图像,在广角照片合成、卫星照片处理、医学图像处理等领域都有应用。早期的图像拼接主要是运用像素值匹配的方法。后来,人们分别在两幅图像中寻找...
  • HDRsoft Photomatix Pro for Mac(照片处理软件)是一款适用于Mac操作系统的数字照片处理软件,它能够调节图片曝光度和通过个曝光源生成HDRI-高动态范围图像高动态范围图像,能够个不同曝光的照片混合成一张照片,...
  • Matlab图像拼接

    千次阅读 2018-11-03 20:58:17
    根据特征点的相互匹配,可以将张小视角的图像拼接成为一张大视角的图像,在广角照片合成、卫星照片处理、医学图像处理等领域都有应用。早期的图像拼接主要是运用像素值匹配的方法。后来,人们分别在两幅图像中寻找...
  • 基于matlab的图像拼接程序

    热门讨论 2014-05-08 12:52:01
    图像拼接(Image Mosaics)技术就是把针对同一场景的相互有部分重叠的一系列图片合成一张大的宽视角的图像,并且要求拼接后的图像最大程度地与原始图像接近,失真尽可能小,没有明显的缝合线川。随着数字图像处理...
  • 基于matlab的图像拼接方法

    万次阅读 多人点赞 2014-11-12 19:16:18
    根据特征点的相互匹配,可以将张小视角的图像拼接成为一张大视角的图像,在广角照片合成、卫星照片处理、医学图像处理等领域都有应用。早期的图像拼接主要是运用像素值匹配的方法。后来,人们分别在两幅图像中寻找...
  • 一张照片纸上可以轻松地布局多种打印尺寸,最大限度的利用纸张,并且一次可以布局多张页面。快速方便地实现批量打印。通过灵活的缩放,旋转,大小适应的调节的方式对照片控制。最佳打印尺寸智能地计算,照片打印缩放...
  • 而位图(Bitmap ),则完全相反,位图是定义每一个像素点的颜色来显示一张图片,它适合显示一张真实的照片。矢量图形的一好处是它的渲染是在运行时开始的,因此它可以自适应不同的屏幕。由于矢量其实保存的只是...
  • Lesson 11 将分开扫描的照片合成到一起 知识点 扫描时的注意事项 知识点 图层Opacity与Fill功能的区别 Lesson 12 将分别拍摄的照片合成为一张 PART 02 进行修整与润色,得到满意的效果 Lesson 13 去聊皮肤上的瑕疵 ...
  • 本软件是专业化立体相机模拟软件,将对分层的每个图层以及整体图像,模拟从不同角度拍照,生成不同角度的多张照片,如果中有变画,也能包含其中,一起生成,互不影响。然后在三立立体实拍合成软件(3D之星IV)中...
  • 互动拍照 — GIF拍照

    2020-03-19 13:52:37
    Gif拍照,其实就是多张照片合成一张“动图”。这种互动形式主要的特点就是图片生动有趣。 但由于gif无法在微信朋友圈分享,必须嵌入网页或者转成视频,所以它的二次传播能力有一点不算问题的问题。 同时,gif是多...
  • Python 告白:除了你还是你

    千次阅读 2019-08-07 23:46:26
    灵感来源于千图成像,多张图合成一张。但考虑到实现难度,以及本着原创练习的原则,将设计思路简化如下: 准备一张主图(合影),若干数量的背景素材(女友照片) 根据主图尺寸,生成等的白色背景,将素材...
  • 号称正确率100%的人脸识别算法

    热门讨论 2009-06-25 19:55:05
    最先进的面部识别软件也会发生50%的偏差。现在,英国格拉斯哥大学的两名心理学家发现了提高识别...也许有一天护照也不再使用现在这样的证件照片,而是用你的多张照片通过数字技术合成的、面部表情更为冷峻的一张图像。
  • 新版Android开发教程.rar

    千次下载 热门讨论 2010-12-14 15:49:11
    � 采用了对有限内存、电池和 CPU 优化过的虚拟机 Dalvik , Android 的运行速度比想象的要快很。 � 运营商(中国移动等)的大力支持,产业链条的热捧。 � 良好的盈利模式( 3/7 开),产业链条的各方:运营商、...
  • 网格相机app是一款非常有趣的照相类应用,它可以将个镜头拍下的照片合成一张图片,除了拍摄固定宽高的小格子相片之外,还可以选择任意宽高的格子,来拍摄较大张的照片,用户可以自行选择前/后相机来拍摄格子影像。...
  • Reflect软件是一款很有趣的换脸应用软件,这款软件可以自动识别到图片中的人脸,用户可以随意的更换面部,功能非常的强大,毫无痕迹的可以合成一张照片,并且软件内还有更的功能可以使用,总会有你意想不到的结果...

空空如也

空空如也

1 2
收藏数 24
精华内容 9
关键字:

多张照片合成一张大图