2017-06-22 41 views
1

我正在爲使用canvas和cordova的移動設備製作非常基本的圖像編輯器。 不幸的是,當涉及畫布時,javascript是記憶的豬,這會導致所有內容在移動設備上徹底崩潰。HTML畫布和內存使用

我使用cropperjs來處理裁剪。 (如果你有更好的,請讓我知道)。 Cropper只允許使用基本的64位數據URL來檢索圖像,這似乎是巨大的內存浪費。 一旦圖像被剪切,我需要重新顯示它再次裁剪。 一個好處是圖像被轉換爲​​黑色和白色的基礎上如何被裁剪。該部分工作得很好,但由於最終使用從畫布提取的dataURL,因此可能會再次使內存大小加倍。

頁面上的按鈕調用此函數。這是麻煩似乎開始的地方。

var originalImage = document.createElement('img'); 
var cropper; 
    function finish() {    
     var data=cropper.getCroppedCanvas().toDataURL(); 
     originalImage.onload = function() { 
      cropper.replace(originalImage, false); 
      cropper.clear(); 
      originalImage.onload=undefined; 
     }; 
     originalImage.src=data; 

    } 

我猜測最終的問題是,dataURL是如此之大,即使沒有在DOM它燒傷內存。這一小段代碼會導致chrome和firefox爲600kb照片添加大約700mb的RAM使用量。 有沒有更好的方法將修改後的圖像存儲在內存中?更小的東西?或者,有沒有辦法制作一個新的臨時文件並加載?或者我完全在錯誤的軌道上?

-Edits爲Blindman67的回答加載

const originalImage = document.createElement('canvas'); 
originalImage.ctx = originalImage.getContext("2d"); 
var cropper; //cropper is created and destroyed on image load, so I can't use const? 
function finish() {     
    const cropped = cropper.getCroppedCanvas(); 
    originalImage.width = cropped.width; 
    originalImage.height = cropped.height; 
    originalImage.ctx.drawImage(cropped,0,0); 
    cropper.clear(); 
    cropper.replace(originalImage , false); //errors, TypeError: t.match is not a function, cropper.min.js (line 11, col 4244) 
} 

代碼從一個文件中的圖片上傳

$('#file').on('change', function (ev) {    
     var f = ev.target.files[0]; 
     var fr = new FileReader(); 

     fr.onload = function (ev2) { 
      console.dir(ev2); 
      if (cropper !== undefined) { 
       cropper.destroy(); 
      } 

      //Probably something wrong with this part 
      $('#img').on("load",function(){ 
       originalImage.width = this.width; 
       originalImage.height = this.height; 
       originalImage.ctx.drawImage(document.getElementById("img"),0,0); 
      }).attr('src', ev2.target.result); 
      //^^^^^ 

      //obvious I've been at this awhile, efficiency went down the tubes \/ 
      var image = document.getElementById("img"); 
      var options = { 
       viewMode: 0, 
       dragMode: 'crop', 
       responsive: true, 
       autoCrop: false, 
       movable: false, 
       scalable: false, 
       zoomable: false, 
       zoomOnTouch: false, 
       zoomOnWheel: false, 
       ready: cropReady 
      }; 
      cropper = new Cropper(image, options); 
     }; 

     fr.readAsDataURL(f); 
    }); 

頁面本身基本上是

<div > 
    <img id="img" style="max-width: 100%; max-height: 100%"/> 
</div> 

- 編輯 它看起來像使用畫布而不是imgs效果不錯。

HTML:

<div class="span-filler"> 
    <img id="img" style="max-width: 100%; max-height: 650px"/> 
    <canvas id="originalImg" style="display:none;max-width: 100%;max-height: 100%;">Please use Chrome or Firefox 
    </canvas> 
</div> 

腳本

var cropper; 
var gBrightness = 0; 
var orgImg = document.getElementById("originalImg"); 
function finish() { 
    cropper.replace(orgImg, true); //doesn't need to data URL oddly 
    var data = cropper.getCroppedCanvas(); 
    orgImg.width = data.width; 
    orgImg.height = data.height; 
    orgImg.getContext("2d").drawImage(data, 0, 0); 
    cropper.replace(orgImg.toDataURL("Image/jpeg"), false); //does need it 
    cropper.clear(); 
} 
$('#file').on('change', function (ev) { 
    var f = ev.target.files[0]; 
    var fr = new FileReader(); 

    fr.onload = function (ev2) { 
     console.dir(ev2); 
     if (cropper !== undefined) { 
      cropper.destroy(); 
     } 
     $('#img').attr('src', ev2.target.result); 
     var image = document.getElementById("img"); 
     var options = { 
      viewMode: 0, 
      dragMode: 'crop', 
      responsive: true, 
      autoCrop: false, 
      movable: false, 
      scalable: false, 
      zoomable: false, 
      zoomOnTouch: false, 
      zoomOnWheel: false, 
      ready: cropReady 
     }; 
     cropper = new Cropper(image, options); 
    }; 

    fr.readAsDataURL(f); 
}); 
function cropReady() { 

    var data = cropper.getCroppedCanvas(); 
    orgImg.width = data.width; 
    orgImg.height = data.height; 
    orgImg.getContext("2d").drawImage(data, 0, 0); 

    processImage(); //converts to black and white using web workers 
} 

//still looking for efficiencies here 
function processImage(brightness) { 
    var canvas = document.createElement('canvas'); 

    var ctx = canvas.getContext("2d"); 
    canvas.width = orgImg.width; 
    canvas.height = orgImg.height; 

    var imgPixels; 
    var imgPixelsSrc = orgImg.getContext("2d").getImageData(0, 0, orgImg.width, orgImg.height); 


    var myWorker = new Worker('js/image_editor/imageWorker.js'); 

    myWorker.onmessage = function (e) { 
     imgPixels = e.data[0]; 
     gBrightness = e.data[2]; 

     ctx.putImageData(imgPixels, 0, 0); 
     cropper.replace(canvas.toDataURL("image/jpeg"), true); 
    }; 
    if (brightness === undefined) { 
     myWorker.postMessage([imgPixelsSrc, true]); 
    } else { 
     myWorker.postMessage([imgPixelsSrc, false, brightness]); 
    } 
} 
+0

此線有沒有意義:originalImage.onload =未定義;還有:cropper.replace。如果可能,請發佈代碼片段!使用簡單的畫布裁剪圖像的一部分。你可以收集圖像數據看看:https://www.w3schools.com/tags/canvas_getimagedata.asp –

+0

當我搜索「簡單的畫布」時,我沒有發現任何明顯的東西。我現在正在使用它,但如果有更好的一個,我願意切換到另一個。 https://github.com/fengyuanchen/cropperjs。 'cropper.replace(originalImage,false);'將htmlimage作爲第一個參數,並更新顏色或全部作爲第二個參數,對於顏色只有true,對於重新加載爲false。由於理論上圖像尺寸已改變,因此需要重新加載。 –

回答

1

畫布可以被用作圖像,並且是HTML圖像元素。沒有必要爲了顯示結果而從畫布轉換爲圖像。

const originalImage = document.createElement('canvas'); 
originalImage.ctx = originalImage.getContext("2d"); 
const cropper; 
function finish() {    
    // check documentation to ensure cropper 
    // is not creating a copy but rather 
    // is returning just a reference 
    const cropped = cropper.getCroppedCanvas();   
    originalImage.width = cropped.width; 
    originalImage.height = cropped.height; 
    originalImage.ctx.drawImage(cropped,0,0); 
    cropper.clear(); 
} 
+0

做了這些編輯需要一點時間,但是'cropper.replace(originalImage,true);'拋出'TypeError:t.match不是來自cropper.min.js的函數。 –

+0

HTMLCanvasElement不是HTMLImageElement。這並不是因爲兩個對象都可以傳遞給'drawImage',它們是一樣的... – Kaiido

+0

如果我將dataurl存儲在sessionStorage中,並且只在內存映像變量中存儲足夠長的時間才能加載裁剪器,那麼清除它。這會有幫助嗎?還是localStorage?或者會導致同樣的問題? –

1

var img = new Image(); 
 
//img.crossOrigin = "Anonymous"; 
 
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg'; 
 
img.onload = function() { 
 
    draw(this); 
 
}; 
 

 
function draw(img) { 
 
    var canvas = document.getElementById('canvas'); 
 
    var ctx = canvas.getContext('2d'); 
 
    ctx.drawImage(img, 0, 0); 
 
    img.style.display = 'none'; 
 
    window['zoomCanvas'] = document.getElementById('zoom'); 
 
    window['zoomctx'] = document.getElementById('zoom').getContext('2d'); 
 
    
 
    var smoothbtn = document.getElementById('smoothbtn'); 
 
    var toggleSmoothing = function(event) { 
 
    zoomctx.imageSmoothingEnabled = this.checked; 
 
    zoomctx.mozImageSmoothingEnabled = this.checked; 
 
    zoomctx.webkitImageSmoothingEnabled = this.checked; 
 
    zoomctx.msImageSmoothingEnabled = this.checked; 
 
    }; 
 
    
 
    
 
    smoothbtn.addEventListener('change', toggleSmoothing); 
 

 
    var zoom = function(event) { 
 
    var x = event.layerX; 
 
    var y = event.layerY; 
 
    zoomctx.drawImage(canvas, 
 
         Math.abs(x - 100), 
 
         Math.abs(y - 100), 
 
         200, 200, 
 
         0, 0, 
 
         200, 200); 
 
    }; 
 

 
    canvas.addEventListener('mousemove', zoom); 
 
    
 
    
 
    function CROP_IT (e){ 
 
    
 
    //this line will collect all data from canvas 
 
    window["IMAGE_CROPED"] = zoomCanvas.toDataURL(); 
 
    localStorage.setItem("savedImageData", zoomCanvas.toDataURL("image/png")); 
 
    
 
    alert(IMAGE_CROPED) 
 
    
 
    } 
 
    
 
    canvas.addEventListener('click', CROP_IT , false); 
 
    
 
    
 
    
 
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas --> 
 

 
<canvas id="canvas" width="300" height="227"></canvas> 
 
<canvas id="zoom" width="300" height="227"></canvas> 
 
<div> 
 
<label for="smoothbtn"> 
 
  <input type="checkbox" name="smoothbtn" checked="false" id="smoothbtn"> 
 
  Enable image smoothing 
 
</label>

+1

雖然不完全是我所需要的,因爲這個頁面本質上是爲了拍攝文檔,所以它需要一個精確的作物。它仍然很有趣,並可能在其他地方幫助我。所以謝謝:) –

+0

這裏是沒有平滑和調整大小的例子.... –