2

我正在使用画布和科尔多瓦为移动设备制作一个非常基本的图像编辑器。不幸的是,当涉及到画布时,javascript 是记忆的猪,这会导致一切在移动设备上彻底崩溃。

我正在使用cropperjs 来处理裁剪。(如果你有更好的,请告诉我)。Cropper 只允许使用 base 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 使用量。有没有更好的方法将修改后的图像存储在内存中?更小的东西?或者,有没有办法制作一个新的临时文件并加载它?还是我完全走错了路?

- 编辑 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]);
    }
}
4

2 回答 2

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();
}
于 2017-06-22T13:08:58.730 回答
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>

于 2017-06-22T13:57:44.183 回答