图片马赛克工具技术咨询:尺寸调整、错误排查及缩放设置
问题与解决方案
用户问题
- 若上传的图片尺寸过大,请问应在何处插入标签进行调整?是否可使用style标签修改?此外,点击create按钮后生成的图片出现错误,烦请排查代码问题。
- 插入图片并点击“Create”后,希望缩小生成图片的比例,请问需修改代码的哪部分?是否还有其他需调整的内容?
相关代码
JavaScript
var TILE_WIDTH = 5; var TILE_HEIGHT = 5; document.getElementById("input").onchange = function() { var reader = new FileReader(); reader.onload = function(e) { // get loaded data and render thumbnail. document.getElementById("image").src = e.target.result; }; // read the image file as a data URL. reader.readAsDataURL(this.files[0]); }; // first function call to create photomosaic function photomosaic(image) { // Dimensions of each tile var tileWidth = TILE_WIDTH; var tileHeight = TILE_HEIGHT; //creating the canvas for photomosaic var canvas = document.createElement('canvas'); var context = canvas.getContext("2d"); canvas.height = image.height; canvas.width = image.width; var imageData = context.getImageData(0, 0, image.width, image.height); var pixels = imageData.data; // Number of mosaic tiles var numTileRows = image.width / tileWidth; var numTileCols = image.height / tileHeight; //canvas copy of image var imageCanvas = document.createElement('canvas'); var imageCanvasContext = canvas.getContext('2d'); imageCanvas.height = image.height; imageCanvas.width = image.width; imageCanvasContext.drawImage(image, 0, 0); //function for finding the average color function averageColor(row, column) { var blockSize = 1, // we can set how many pixels to skip data, width, height, i = -4, length, rgb = { r: 0, g: 0, b: 0 }, count = 0; try { data = imageCanvasContext.getImageData(column * TILE_WIDTH, row * TILE_HEIGHT, TILE_HEIGHT, TILE_WIDTH); } catch (e) { alert('Not happening this time!'); return rgb; } length = data.data.length; while ((i += blockSize * 4) < length) { ++count; rgb.r += data.data[i]; rgb.g += data.data[i + 1]; rgb.b += data.data[i + 2]; } // ~~ used to floor values rgb.r = ~~(rgb.r / count); rgb.g = ~~(rgb.g / count); rgb.b = ~~(rgb.b / count); return rgb; } // Loop through each tile for (var r = 0; r < numTileRows; r++) { for (var c = 0; c < numTileCols; c++) { // Set the pixel values for each tile var rgb = averageColor(r, c) var red = rgb.r; var green = rgb.g; var blue = rgb.b; // Loop through each tile pixel for (var tr = 0; tr < tileHeight; tr++) { for (var tc = 0; tc < tileWidth; tc++) { // Calculate the true position of the tile pixel var trueRow = (r * tileHeight) + tr; var trueCol = (c * tileWidth) + tc; // Calculate the position of the current pixel in the array var pos = (trueRow * (imageData.width * 4)) + (trueCol * 4); // Assign the colour to each pixel pixels[pos + 0] = red; pixels[pos + 1] = green; pixels[pos + 2] = blue; pixels[pos + 3] = 255; }; }; }; }; // Draw image data to the canvas context.putImageData(imageData, 0, 0); return canvas; } function create() { var image = document.getElementById('image'); var canvas = photomosaic(image); document.getElementById("output").appendChild(canvas); };
CSS
#output, .container { text-align: center; } .inputDiv { margin: 20px 0px; }
HTML
<div class="container"> <img id="image" src="https://via.placeholder.com/100" /> <div class="inputDiv"> <input id="input" type="file" accept="image/*"> <button onclick="create()">create</button> </div> <div id='output'></div> </div>
解决方案
问题1解答
图片尺寸调整
- 可以直接通过
style标签修改上传预览图的显示尺寸,比如给<img id="image">添加内联样式:<img id="image" src="https://via.placeholder.com/100" style="max-width: 500px; max-height: 500px;" /> - 或者在CSS中统一控制:
#image { max-width: 100%; max-height: 500px; object-fit: contain; } - 生成的马赛克画布也可以通过CSS限制显示大小,避免页面溢出:
#output canvas { max-width: 100%; height: auto; }
代码错误排查
原代码存在3处关键错误:
- imageCanvas上下文指向错误:
原代码中var imageCanvasContext = canvas.getContext('2d');应该改为var imageCanvasContext = imageCanvas.getContext('2d');,否则会复用主画布的上下文,导致获取不到上传图片的像素数据。 - 行列计算颠倒:
numTileRows(行数)应该基于图片高度计算,numTileCols(列数)基于宽度计算,原代码写反了,修正后:var numTileRows = image.height / tileHeight; var numTileCols = image.width / tileWidth; - getImageData参数顺序错误:
getImageData的参数是x, y, width, height,原代码中把宽高顺序写反了,修正后:data = imageCanvasContext.getImageData(column * tileWidth, row * tileHeight, tileWidth, tileHeight);
问题2解答
缩小生成图片比例
可以通过添加缩放因子来调整生成画布的尺寸,修改步骤如下:
- 定义缩放因子:在
photomosaic函数开头添加缩放比例,比如var scaleFactor = 0.5;(表示缩小到原尺寸的50%)。 - 调整画布尺寸:
var canvas = document.createElement('canvas'); var context = canvas.getContext("2d"); canvas.height = image.height * scaleFactor; canvas.width = image.width * scaleFactor; - 调整图片副本画布的尺寸与绘制:
var imageCanvas = document.createElement('canvas'); var imageCanvasContext = imageCanvas.getContext('2d'); imageCanvas.height = image.height * scaleFactor; imageCanvas.width = image.width * scaleFactor; imageCanvasContext.drawImage(image, 0, 0, imageCanvas.width, imageCanvas.height); - 调整像素数据与循环计算:
由于画布尺寸缩放,getImageData和循环中的行列计算要基于缩放后的尺寸,修正imageData和行列数:var imageData = context.getImageData(0, 0, canvas.width, canvas.height); var numTileRows = canvas.height / tileHeight; var numTileCols = canvas.width / tileWidth; - 可选:同步调整预览图尺寸:如果需要让预览图和生成图尺寸匹配,也可以给
<img id="image">添加对应缩放样式。
内容的提问来源于stack exchange,提问作者semi
相关产品推荐
相关产品推荐

