2014-09-17 4 views
0

캔버스가 아닌 페이지에 저장 버튼을 추가하려고합니다. 모든 온라인 예제를 시도해 볼 때 캔버스에 저장하지 못하는 것 같습니다. 기본적으로 저장 단추를 클릭하여 이미지로 자동 다운로드하거나 이름 바꾸기, 이동 및 저장 등을 위해 내 컴퓨터 창에 저장을 엽니 다. www.jsfiddle.net/dsj00qoy/ 16/KineticJS Canvas 컴퓨터에 저장 버튼

<button id="save">Save as image</button> 
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.2.min.js"></script> 
      <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>  <script src="http://eligrey.com/demos/FileSaver.js/Blob.js"></script> 
      <script src="http://eligrey.com/demos/FileSaver.js/canvas-toBlob.js"></script> 
      <script src="http://eligrey.com/demos/FileSaver.js/FileSaver.js"></script> 
<script type="text/javascript" src="https://53d4e26fadb6e09777fddd385fe78ac4b63826d5.googledrive.com/host/0B71KNg66uHaYR014NlB4b0c0ZWc/btq1.js"></script> 
+0

편집하여 내 페이지에서 일부 코딩을 추가하십시오. 위 코딩은 캔버스 자체와 다른 HTML입니다. Google 드라이브에서 js의 마지막 줄은 캔버스 자체에 대한 내 js 파일입니다. –

답변

0

좋은 뉴스 :

새로운 canvas.toBlob 방법은 당신이 덩어리로 캔버스를 변환 한 다음에 이미지로 사용자 다운로드 방울을 수 있도록 saveAs을 사용할 수 있습니다 자신의 로컬 드라이브.

나쁜 뉴스

:

대부분의 브라우저는 아직 .toBlobsaveAs 구현하지 않았습니다.

는 해결 방법 :

엘리 그레이는 기존 브라우저에서 toBlob + 다른 이름으로 저장을 사용할 수 있도록 좋은 심 (shim)를 작성했습니다 :

https://github.com/eligrey/FileSaver.js

여기 엘리 회색의 심의를 사용하는 예제입니다.

KineticJS는 실제로 캔버스 (레이어)의 세트 (단계)입니다. KineticJS의 경우 모든 KineticJS 레이어가 포함 된 1 개의 캔버스를 만드는 추가 단계가 있습니다.

  • 스테이지에서 imageURL을 만듭니다 (stage.toDataURL 참조).

  • imageURL에서 이미지를 만듭니다.

  • 메모리 내 캔버스를 만듭니다.

  • Draw 이미지를 메모리 캔버스에 렌더링합니다.

  • 사용자가 버튼을 누르고 스테이지로 로컬 드라이브에 이미지로 저장할 수 있도록 메모리 캔버스와 Eli Gray의 심을 사용하십시오.

    var canvas=document.getElementById("canvas"); 
     
    var ctx=canvas.getContext("2d"); 
     
    
     
    var img=new Image() 
     
    img.onload=function(){ 
     
        ctx.fillStyle="red"; 
     
        ctx.drawImage(img,0,0); 
     
        ctx.fillRect(100,100,50,30); 
     
    } 
     
    img.crossOrigin="anonymous"; 
     
    img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/ship.png"; 
     
    
     
    
     
    $("#save").click(function(){ 
     
        canvas.toBlob(function(blob){ saveAs(blob,"temp4.png"); }); 
     
    });
    body{ background-color: ivory; } 
     
    canvas{border:1px solid red;}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
     
    <button id="save">Save</button><br> 
     
    <canvas id="canvas" width=300 height=300></canvas> 
     
    
     
    
     
    <script> 
     
        /* FileSaver.js 
     
          * A saveAs() FileSaver implementation. 
     
          * 2014-08-29 
     
          * 
     
          * By Eli Grey, http://eligrey.com 
     
          * License: X11/MIT 
     
          * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 
     
          */ 
     
    
     
        /*global self */ 
     
        /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 
     
    
     
        /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 
     
    
     
        var saveAs = saveAs 
     
        // IE 10+ (native saveAs) 
     
        || (typeof navigator !== "undefined" && 
     
         navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) 
     
        // Everyone else 
     
        || (function(view) { 
     
        "use strict"; 
     
        // IE <10 is explicitly unsupported 
     
        if (typeof navigator !== "undefined" && 
     
         /MSIE [1-9]\./.test(navigator.userAgent)) { 
     
         return; 
     
        } 
     
        var 
     
        doc = view.document 
     
        // only get URL when necessary in case Blob.js hasn't overridden it yet 
     
        , get_URL = function() { 
     
         return view.URL || view.webkitURL || view; 
     
        } 
     
        , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 
     
        , can_use_save_link = "download" in save_link 
     
        , click = function(node) { 
     
         var event = doc.createEvent("MouseEvents"); 
     
         event.initMouseEvent(
     
         "click", true, false, view, 0, 0, 0, 0, 0 
     
         , false, false, false, false, 0, null 
     
        ); 
     
         node.dispatchEvent(event); 
     
        } 
     
        , webkit_req_fs = view.webkitRequestFileSystem 
     
        , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 
     
        , throw_outside = function(ex) { 
     
         (view.setImmediate || view.setTimeout)(function() { 
     
         throw ex; 
     
         }, 0); 
     
        } 
     
        , force_saveable_type = "application/octet-stream" 
     
        , fs_min_size = 0 
     
        // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 for 
     
        // the reasoning behind the timeout and revocation flow 
     
        , arbitrary_revoke_timeout = 10 
     
        , revoke = function(file) { 
     
         var revoker = function() { 
     
         if (typeof file === "string") { // file is an object URL 
     
          get_URL().revokeObjectURL(file); 
     
         } else { // file is a File 
     
          file.remove(); 
     
         } 
     
         }; 
     
         if (view.chrome) { 
     
         revoker(); 
     
         } else { 
     
         setTimeout(revoker, arbitrary_revoke_timeout); 
     
         } 
     
        } 
     
        , dispatch = function(filesaver, event_types, event) { 
     
         event_types = [].concat(event_types); 
     
         var i = event_types.length; 
     
         while (i--) { 
     
         var listener = filesaver["on" + event_types[i]]; 
     
         if (typeof listener === "function") { 
     
          try { 
     
          listener.call(filesaver, event || filesaver); 
     
          } catch (ex) { 
     
          throw_outside(ex); 
     
          } 
     
         } 
     
         } 
     
        } 
     
        , FileSaver = function(blob, name) { 
     
         // First try a.download, then web filesystem, then object URLs 
     
         var 
     
         filesaver = this 
     
         , type = blob.type 
     
         , blob_changed = false 
     
         , object_url 
     
         , target_view 
     
         , dispatch_all = function() { 
     
         dispatch(filesaver, "writestart progress write writeend".split(" ")); 
     
         } 
     
         // on any filesys errors revert to saving with object URLs 
     
         , fs_error = function() { 
     
         // don't create more object URLs than needed 
     
         if (blob_changed || !object_url) { 
     
          object_url = get_URL().createObjectURL(blob); 
     
         } 
     
         if (target_view) { 
     
          target_view.location.href = object_url; 
     
         } else { 
     
          var new_tab = view.open(object_url, "_blank"); 
     
          if (new_tab == undefined && typeof safari !== "undefined") { 
     
          //Apple do not allow window.open, see http://bit.ly/1kZffRI 
     
          view.location.href = object_url 
     
          } 
     
         } 
     
         filesaver.readyState = filesaver.DONE; 
     
         dispatch_all(); 
     
         revoke(object_url); 
     
         } 
     
         , abortable = function(func) { 
     
         return function() { 
     
          if (filesaver.readyState !== filesaver.DONE) { 
     
          return func.apply(this, arguments); 
     
          } 
     
         }; 
     
         } 
     
         , create_if_not_found = {create: true, exclusive: false} 
     
         , slice 
     
         ; 
     
         filesaver.readyState = filesaver.INIT; 
     
         if (!name) { 
     
         name = "download"; 
     
         } 
     
         if (can_use_save_link) { 
     
         object_url = get_URL().createObjectURL(blob); 
     
         save_link.href = object_url; 
     
         save_link.download = name; 
     
         click(save_link); 
     
         filesaver.readyState = filesaver.DONE; 
     
         dispatch_all(); 
     
         revoke(object_url); 
     
         return; 
     
         } 
     
         // Object and web filesystem URLs have a problem saving in Google Chrome when 
     
         // viewed in a tab, so I force save with application/octet-stream 
     
         // http://code.google.com/p/chromium/issues/detail?id=91158 
     
         // Update: Google errantly closed 91158, I submitted it again: 
     
         // https://code.google.com/p/chromium/issues/detail?id=389642 
     
         if (view.chrome && type && type !== force_saveable_type) { 
     
         slice = blob.slice || blob.webkitSlice; 
     
         blob = slice.call(blob, 0, blob.size, force_saveable_type); 
     
         blob_changed = true; 
     
         } 
     
         // Since I can't be sure that the guessed media type will trigger a download 
     
         // in WebKit, I append .download to the filename. 
     
         // https://bugs.webkit.org/show_bug.cgi?id=65440 
     
         if (webkit_req_fs && name !== "download") { 
     
         name += ".download"; 
     
         } 
     
         if (type === force_saveable_type || webkit_req_fs) { 
     
         target_view = view; 
     
         } 
     
         if (!req_fs) { 
     
         fs_error(); 
     
         return; 
     
         } 
     
         fs_min_size += blob.size; 
     
         req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 
     
         fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 
     
          var save = function() { 
     
          dir.getFile(name, create_if_not_found, abortable(function(file) { 
     
           file.createWriter(abortable(function(writer) { 
     
           writer.onwriteend = function(event) { 
     
            target_view.location.href = file.toURL(); 
     
            filesaver.readyState = filesaver.DONE; 
     
            dispatch(filesaver, "writeend", event); 
     
            revoke(file); 
     
           }; 
     
           writer.onerror = function() { 
     
            var error = writer.error; 
     
            if (error.code !== error.ABORT_ERR) { 
     
            fs_error(); 
     
            } 
     
           }; 
     
           "writestart progress write abort".split(" ").forEach(function(event) { 
     
            writer["on" + event] = filesaver["on" + event]; 
     
           }); 
     
           writer.write(blob); 
     
           filesaver.abort = function() { 
     
            writer.abort(); 
     
            filesaver.readyState = filesaver.DONE; 
     
           }; 
     
           filesaver.readyState = filesaver.WRITING; 
     
           }), fs_error); 
     
          }), fs_error); 
     
          }; 
     
          dir.getFile(name, {create: false}, abortable(function(file) { 
     
          // delete file if it already exists 
     
          file.remove(); 
     
          save(); 
     
          }), abortable(function(ex) { 
     
          if (ex.code === ex.NOT_FOUND_ERR) { 
     
           save(); 
     
          } else { 
     
           fs_error(); 
     
          } 
     
          })); 
     
         }), fs_error); 
     
         }), fs_error); 
     
        } 
     
        , FS_proto = FileSaver.prototype 
     
        , saveAs = function(blob, name) { 
     
         return new FileSaver(blob, name); 
     
        } 
     
        ; 
     
        FS_proto.abort = function() { 
     
         var filesaver = this; 
     
         filesaver.readyState = filesaver.DONE; 
     
         dispatch(filesaver, "abort"); 
     
        }; 
     
        FS_proto.readyState = FS_proto.INIT = 0; 
     
        FS_proto.WRITING = 1; 
     
        FS_proto.DONE = 2; 
     
    
     
        FS_proto.error = 
     
         FS_proto.onwritestart = 
     
         FS_proto.onprogress = 
     
         FS_proto.onwrite = 
     
         FS_proto.onabort = 
     
         FS_proto.onerror = 
     
         FS_proto.onwriteend = 
     
         null; 
     
    
     
        return saveAs; 
     
        }(
     
        typeof self !== "undefined" && self 
     
        || typeof window !== "undefined" && window 
     
        || this.content 
     
    )); 
     
        // `self` is undefined in Firefox for Android content script context 
     
        // while `this` is nsIContentFrameMessageManager 
     
        // with an attribute `content` that corresponds to the window 
     
    
     
        if (typeof module !== "undefined" && module !== null) { 
     
        module.exports = saveAs; 
     
        } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { 
     
        define([], function() { 
     
         return saveAs; 
     
        }); 
     
        } 
     
    </script> 
     
    
     
    <script> 
     
        /* canvas-toBlob.js 
     
          * A canvas.toBlob() implementation. 
     
          * 2013-12-27 
     
          * 
     
          * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr 
     
          * License: X11/MIT 
     
          * See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md 
     
          */ 
     
    
     
        /*global self */ 
     
        /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 
     
           plusplus: true */ 
     
    
     
        /*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */ 
     
    
     
        (function(view) { 
     
        "use strict"; 
     
        var 
     
        Uint8Array = view.Uint8Array 
     
        , HTMLCanvasElement = view.HTMLCanvasElement 
     
        , canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype 
     
        , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i 
     
        , to_data_url = "toDataURL" 
     
        , base64_ranks 
     
        , decode_base64 = function(base64) { 
     
         var 
     
         len = base64.length 
     
         , buffer = new Uint8Array(len/4 * 3 | 0) 
     
         , i = 0 
     
         , outptr = 0 
     
         , last = [0, 0] 
     
         , state = 0 
     
         , save = 0 
     
         , rank 
     
         , code 
     
         , undef 
     
         ; 
     
         while (len--) { 
     
         code = base64.charCodeAt(i++); 
     
         rank = base64_ranks[code-43]; 
     
         if (rank !== 255 && rank !== undef) { 
     
          last[1] = last[0]; 
     
          last[0] = code; 
     
          save = (save << 6) | rank; 
     
          state++; 
     
          if (state === 4) { 
     
          buffer[outptr++] = save >>> 16; 
     
          if (last[1] !== 61 /* padding character */) { 
     
           buffer[outptr++] = save >>> 8; 
     
          } 
     
          if (last[0] !== 61 /* padding character */) { 
     
           buffer[outptr++] = save; 
     
          } 
     
          state = 0; 
     
          } 
     
         } 
     
         } 
     
         // 2/3 chance there's going to be some null bytes at the end, but that 
     
         // doesn't really matter with most image formats. 
     
         // If it somehow matters for you, truncate the buffer up outptr. 
     
         return buffer; 
     
        } 
     
        ; 
     
        if (Uint8Array) { 
     
         base64_ranks = new Uint8Array([ 
     
         62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1 
     
         , -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 
     
         , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 
     
         , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 
     
         , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 
     
         ]); 
     
        } 
     
        if (HTMLCanvasElement && !canvas_proto.toBlob) { 
     
         canvas_proto.toBlob = function(callback, type /*, ...args*/) { 
     
         if (!type) { 
     
          type = "image/png"; 
     
         } if (this.mozGetAsFile) { 
     
          callback(this.mozGetAsFile("canvas", type)); 
     
          return; 
     
         } if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) { 
     
          callback(this.msToBlob()); 
     
          return; 
     
         } 
     
    
     
         var 
     
         args = Array.prototype.slice.call(arguments, 1) 
     
         , dataURI = this[to_data_url].apply(this, args) 
     
         , header_end = dataURI.indexOf(",") 
     
         , data = dataURI.substring(header_end + 1) 
     
         , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end)) 
     
         , blob 
     
         ; 
     
         if (Blob.fake) { 
     
          // no reason to decode a data: URI that's just going to become a data URI again 
     
          blob = new Blob 
     
          if (is_base64) { 
     
          blob.encoding = "base64"; 
     
          } else { 
     
          blob.encoding = "URI"; 
     
          } 
     
          blob.data = data; 
     
          blob.size = data.length; 
     
         } else if (Uint8Array) { 
     
          if (is_base64) { 
     
          blob = new Blob([decode_base64(data)], {type: type}); 
     
          } else { 
     
          blob = new Blob([decodeURIComponent(data)], {type: type}); 
     
          } 
     
         } 
     
         callback(blob); 
     
         }; 
     
    
     
         if (canvas_proto.toDataURLHD) { 
     
         canvas_proto.toBlobHD = function() { 
     
          to_data_url = "toDataURLHD"; 
     
          var blob = this.toBlob(); 
     
          to_data_url = "toDataURL"; 
     
          return blob; 
     
         } 
     
         } else { 
     
         canvas_proto.toBlobHD = canvas_proto.toBlob; 
     
         } 
     
        } 
     
        }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); 
     
    
     
    
     
    </script>

[스크립트에 대한 - 그냥 내 의견]

아, 그래 ... 스크립트 조직. 요리사처럼 모든 사람들이 자신의 취향에 맞게 구성 방법을 달리하는 것처럼 보입니다. 개인적으로, 나는 이렇게 해. (1) jQuery와 같은 타사 소프트웨어에는 항상 CDN을 사용하십시오. 왜냐하면 jQuery (및 기타 타사 제품)가 이미 사용자의 장치에 캐시되어 있기 때문입니다. 브라우저에 jQuery가 필요하고 이미 캐시 된 경우 캐시 된 버전이 사용되며 중복 jQuery도 다운로드되지 않습니다. 캐싱은 URL을 기반으로 이루어 지므로 가능한 경우 잘 알려진 CDN을 사용하십시오. (2a) 스크립트가10K이면 총 하나의 scripts.js 파일에 넣고 스크립트 태그가있는 페이지에 포함 시키십시오.(2b) 스크립트의 총 수가 10K를 초과하면 스크립트를 축소 한 다음 script 태그가있는 페이지에 축소 된 script.js를 다시 포함시킵니다. 위로 개발 컴퓨터에서 코드의 유지 관리가 필요할 경우에 대비하여 축소 및 축소되지 않은 스크립트 파일 복사본을 보관합니다. 더 많은 생각 : 많은 페이지에 공통적 인 무거운 스크립트를 사용하는 사이트의 경우 해당 스크립트를 별도의 commonScripts.js로 축소합니다. 무거운 페이지 특정 스크립트의 경우 해당 스크립트를 필요한 페이지에만 포함 된 별도의 스크립트 파일로 축소합니다. 어쨌든, 이것들은 법이 아닙니다. 제가 스크립트를 어떻게 구성하는지. 건배!

+0

그래서 나는 내 html 페이지에서 소스로 사용하고있는 모든 캔버스 항목이있는 .js 파일을 가지고 있습니다. 이 코드를 js에 넣어야합니까, 아니면 그냥 나머지 코드를 페이지에 넣을 수 있습니까? 위의 편집에서 주 코드를 넣으십시오. 컨테이너 자체가 위에 있습니다. . –

+0

스크립트 처리에 관한 제 의견은 설명을하기에는 너무 길어서 답변이 조금 추가되었습니다. 건배! – markE

+0

이것은 여전히 ​​작동하지 않는 것 같습니다. 다른 사이트에서 호스팅되는 이미지를 사용하는 것과 관련이 있습니까? 나는 당신이 다른 사이트의 사진을 가지고 있다면 그것을 깨뜨린 어딘가에있는 것을 보았습니까? Chrome을 사용하고 있는데 캔버스를 마우스 오른쪽 버튼으로 클릭하면 저장할 수 있고 모든 것을 표시하지만 버튼을 클릭하면 대신 저장할 수 있으므로 삭제해야합니다. 오른쪽 클릭과 저장이 IE 나 모질라에서 작동하는지 아직 테스트하지 않았기 때문에 내가 사용하는 브라우저가 크로스 브라우저가 될 것인지 확인하고 싶습니다. –

관련 문제