zoukankan      html  css  js  c++  java
  • JavaScript修改Canvas图片

     

    用JavaScript修改Canvas图片的分辨率(DPI)

     

     

     

    应用场景:

    仓库每次发货需要打印标签, Canvas根据从数据库读取的产品信息可以生成标签JPG, 但是这个JPG图片的默认分辨率(DPI)是72

    这个DPI太低, 导致打印出来的图片会很模糊.

    修改DPI的常规做法是把图片上传到服务器用C#修改DPI后再下载到服务端

    但是心里觉得很憋屈, 分明已经在客户端生成了图片, 仅仅为了修改一个很小的标记(DPI信息只是JPEG格式的一个头部META)要上传一张很大的图片到服务端折腾一遭.

    后来使用了下面的方法

    用JavaScript直接修改了DPI

    这里不贴源码, 仅提供解决思路, 希望需要的朋友自己亲手试一下

    既然知道DPI只是JPEG格式的头部信息, 并且是很小的一部分, 而base64属于流编码, 那么canvas.toDataURL()以后的base64字符串中, 这个DPI信息所处的位置应该也是固定的

    1. 用图片处理程序(我用的是Fireworks)生成两张内容一样的JPG图片, 仅修改其DPI, A图片的DPI是72, B图片的DPI是300
      这里为了确认起见, 使用UE对比一下两个文件, 确实只有头部几个字节不一样
    2. 用C#读取A/B图片, 分别编码成BASE64, 生成A.txt和B.txt
    3. 用UE或其他文本编辑器对比两个文本文件, 找出不一样的部分, 你会发现只有靠近头部的不到10个字符不一样
    4. 重复以上实验, 用不同的图片, 会发现最后总是那固定的几个字符不一样, 并且只要DPI一样, 那固定位置的几个字符也是一样的
    5. 在浏览器端用canvas.toDataURL生成jpg图片的base64字符, 然后修改字符中刚才固定位置的字符为测试时DPI为300的特征字符

    OK, 现在你已经获得了一个DPI为300的JPG图片了.

    有兴趣的朋友可以去研究一下BASE64编码, 然后做成一个函数来计算不同DPI所对应的特征字符

    至于二进制状态的那几个自己, 用计算器按一下就会发现那就是直接存储的DPI数值

    MORE:

    在公司的项目中, 操作人员每次不同批次的图片会习惯于保存在一个固定的文件夹里, canvas生成的图片另存为的时候默认文件名总是 canvas.jpg

    这里如果使用它们所习惯的批次号.jpg作为保存的默认文件名体验会好很多

    这里有两种方案,

    1. 去Google找一个叫做downloadify的Flash组件, 可以保证点击"下载"按钮的时候跳出一个选择保存位置的对话框, 并且默认的文件名可以用js指定
    2. 使用HTML5的download属性加在A标签里, 这个方案更简单, 不过Firefox/Chrome会直接保存到默认下载位置, 不会让用户选择, 而右键另存为又会失去默认文件名的作用

    两种方案各有利弊吧, 具体看操作人员的使用习惯

     
     
    分类: Crazy Code

    走进AngularJs(三)自定义指令-----(上)

     

    一、有感而发的一些话

      在学习ng之前有听前辈说过,angular上手比较难,初学者可能不太适应其语法以及思想。随着对ng探索的一步步深入,也确实感觉到了这一点,尤其是框架内部的某些执行机制,其复杂程度并非是我现在的功力能够理解的,只能是知其皮毛。我现在学习的途径是官方文档 + AngularJS在github上的中文粗译版(https://github.com/basestyle/angularjs-cn)+ 网上搜到的一些文章。鉴于本人资质平平以前也只用过jQuery,目前只能做到理解ng的API文档,相关特性的使用方式。故博客的主要内容也就是记载一些我的理解与应用,对ng框架内部的机制只做必要的了解,暂不深入探究。

      智商捉急,就到这里~

      接下来聊聊angular的指令机制。angular通过指令的方式实现了HTML的扩展,增强后的HTML就好比是究极进化后的暴龙兽,不仅长相焕然一新,同时也获得了很多强大的技能。更厉害的是,你还可以自定义指令,这就意味着HTML标签的范围可以扩展到无穷大,ng赋予了你造物主的能力。作为angular的精华之一,指令相关的知识也很多,本篇开始探索自定义指令的方方面面。为了不让我的篇幅再拉那么长,我识趣的在标题后面加了(上),你懂的。

    二、指令的编译过程及命名方式

      在开始自定义指令之前,我们有必要了解一下指令在框架中的执行流程。这部分内容我没有自己研究,只是照搬了别人的说法:

    1. 浏览器得到 HTML 字符串内容,解析得到 DOM 结构。
    2. ng 引入,把 DOM 结构扔给 $compile 函数处理:

        ①   找出 DOM 结构中有变量占位符

        ②   匹配找出 DOM 中包含的所有指令引用

        ③   把指令关联到 DOM

        ④   关联到 DOM 的多个指令按权重排列

        ⑤   执行指令中的 compile 函数(改变 DOM 结构,返回 link 函数)

        ⑥   得到的所有 link 函数组成一个列表作为 $compile 函数的返回

      3. 执行 link 函数(连接模板的 scope)。

      这里注意区别一下$compile和compile,前者是ng内部的编译服务,后者是指令中的编译函数,两者发挥作用的范围不同。compile和link函数息息相关又有所区别,这个在后面会讲。了解执行流程对后面的理解会有帮助。

      在这里我小小的多嘴一下,有些人可能会问,angular不就是一个js框架吗,怎么还能跟编译扯上呢,又不是像C++那样的高级语言。其实此编译非彼编译,ng编译的工作是解析指令啦,绑定监听器啦,替换模板中的变量啦这些。因为工作方式很像高级语言编辑中的递归、堆栈过程,所以起名为编译,不要疑惑。

      指令的几种使用方式如下:

      作为标签:<my-dir></my-dir>

      作为属性:<span my-dir="exp"></span>

      作为注释:<!-- directive: my-dir exp -->

      作为类名:<span class="my-dir: exp;"></span>

      其实常用的就是作为标签和属性,下面两种用法目前还没见过,姑且留个印象。我们自定义的指令就是要支持这样的用法。

      关于自定义指令的命名,你可以随便怎么起名字都行,官方是推荐用[命名空间-指令名称]这样的方式,像ng-controller。不过你可千万不要用ng-前缀了,防止与系统自带的指令重名。另外一个需知道的地方,指令命名时用驼峰规则,使用时用-分割各单词。如:定义myDirective,使用时像这样:<my-directive>。

    三、自定义指令的配置参数

      下面是定义一个标准指令的示例,可配置的参数包括以下部分:

    复制代码
    myModule.directive('namespaceDirectiveName', function factory(injectables) {
    
            var directiveDefinitionObject = {
    
                restrict: string,//指令的使用方式,包括标签,属性,类,注释
    
                priority: number,//指令执行的优先级
    
                template: string,//指令使用的模板,用HTML字符串的形式表示
    
                templateUrl: string,//从指定的url地址加载模板
    
                replace: bool,//是否用模板替换当前元素,若为false,则append在当前元素上
    
                transclude: bool,//是否将当前元素的内容转移到模板中
    
                scope: bool or object,//指定指令的作用域
    
                controller: function controllerConstructor($scope, $element, $attrs, $transclude){...},//定义与其他指令进行交互的接口函数
    
                require: string,//指定需要依赖的其他指令
    
                link: function postLink(scope, iElement, iAttrs) {...},//以编程的方式操作DOM,包括添加监听器等
    
                compile: function compile(tElement, tAttrs, transclude){
    
                    return: {
    
                        pre: function preLink(scope, iElement, iAttrs, controller){...},
    
                        post: function postLink(scope, iElement, iAttrs, controller){...}
    
                    }
    
                }//编程的方式修改DOM模板的副本,可以返回链接函数
    
            };
    
            return directiveDefinitionObject;
    
    });
    复制代码

             看上去好复杂的样子啊~定义一个指令需要这么多步骤嘛?当然不是,你可以根据自己的需要来选择使用哪些参数。事实上priority和compile用的比较少,template和templateUrl又是互斥的,两者选其一即可。所以不必紧张,接下来分别学习一下这些参数,我将先从一个简单的例子开始。为了易于理解和我以后翻看的时候还能看明白,我尽量使用有语义的命名,而不是像test1,test2这样。

             例子的代码如下:

    复制代码
    var app = angular.module('MyApp', [], function(){console.log('here')});
    app.directive('sayHello',function(){ return { restrict : 'E', template : '<div>hello</div>' }; })
    复制代码

             然后在页面中,我们就可以使用这个名为sayHello的指令了,它的作用就是输出一个hello单词。像这样使用:

    <say-hello></say-hello>

             这样页面就会显示出hello了,看一下生成的代码:

       

             稍稍解释一下我们用到的两个参数,restirct用来指定指令的使用类型,其取值及含义如下:

    取值

    含义

    使用示例

    E

    标签

    <my-menu title=Products></my-menu>

    A

    属性

    <div my-menu=Products></div>

    C

    <div class="my-menu":Products></div>

    M

    注释

    <!--directive:my-menu Products-->

             默认值是A。也可以使用这些值的组合,如EA,EC等等。我们这里指定为E,那么它就可以像标签一样使用了。如果指定为A,我们使用起来应该像这样:

    <div say-hello></div>

             从生成的代码中,你也看到了template的作用,它就是描述你的指令长什么样子,这部分内容将出现在页面中,即该指令所在的模板中,既然是模板中,template的内容中也可以使用ng-modle等其他指令,就像在模板中使用一样。

      在上面生成的代码中,我们看到了<div>hello</div>外面还包着一层<say-hello>标签,如果我们不想要这一层多余的东西了,replace就派上用场了,在配置中将replace赋值为true,将得到如下结构:

       

             replace的作用正如其名,将指令标签替换为了temple中定义的内容。不写的话默认为false。

             上面的template未免也太简单了,如果你的模板HTML较复杂,如自定义一个ui组件指令,难道要拼接老长的字符串?当然不需要,此时只需用templateUrl便可解决问题。你可以将指令的模板单独命名为一个html文件,然后在指令定义中使用templateUrl指定好文件的路径即可,如:

    templateUrl : ‘helloTemplate.html’

             系统会自动发一个http请求来获取到对应的模板内容。是不是很方便呢,你不用纠结于拼接字符串的烦恼了。如果你是一个追求完美的有考虑性能的工程师,可能会发问:那这样的话岂不是要牺牲一个http请求?

             这也不用担心,因为ng的模板还可以用另外一种方式定义,那就是使用<script>标签。使用起来如下:

    <script type="text/ng-template" id="helloTemplate.html">
             <div>hello</div>
    </script>

             你可以把这段代码写在页面头部,这样就不必去请求它了。在实际项目中,你也可以将所有的模板内容集中在一个文件中,只加载一次,然后根据id来取用。

             接下来我们来看另一个比较有用的配置:transclude,定义是否将当前元素的内容转移到模板中。看解释有点抽象,不过亲手试试就很清楚了,看下面的代码:

    复制代码
    app.directive('sayHello',function(){
                       return {
                                restrict : 'E',
                                template : '<div>hello,<b ng-transclude></b></div>',
                                replace : true,
                                transclude : true
                       };
             })
    复制代码

             指定了transclude为true,并且template修改了一下,加了一个<b>标签,并在上面使用了ng-transclude指令,用来告诉指令把内容转移到的位置。那我们要转移的内容是什么呢?请看使用指令时的变化:

    <say-hello>美女</say-hello>

             内容是什么你也看到了哈~在运行的时候,美女将会被转移到<b>标签中,原来此配置的作用就是——乾坤大挪移!看效果:

       

             这个还是很有用的,因为你定义的指令不可能老是那么简单,只有一个空标签。当你需要对指令中的内容进行处理时,此参数便大有可用。

    四、结束

      看前面写的两篇,感觉篇幅太长了,可能会有人耐不住性子看完,故本篇先介绍几个比较简单的参数,先拿软的来捏一捏,更复杂的用法还在后头。我们将真正用一下自定义指令,起码也搞个像样的ui组件出来,这样才算是学会了。

      今天爬香山回来,累的够呛,时辰不早,收工睡觉~

     
     
     
  • 相关阅读:
    C# post请求,Json转换实体类
    jq div 托拉拽
    json转换成实体类
    C# 队列、锁、异步
    关于C#调用protobuf 序列化和反序列化
    关于System.Data.Entity.Infrastructure.DbUpdateException 的问题
    C# 本地CSS和JS引用无问题,部署服务器之后出现500错误
    windows服务
    下拉加载更多DEMO(js实现)
    禁用iPhone手机浏览器上给电话号码自动加上的link样式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3393475.html
Copyright © 2011-2022 走看看