Loupe issues fixed #378 (#382)

This commit is contained in:
Jacco Kulman 2018-08-09 00:27:01 +02:00 committed by DD Liu
parent 680b403de6
commit 8056a788e7
6 changed files with 71 additions and 53 deletions

View file

@ -23,7 +23,7 @@
"url": "git+ssh://git@github.com/LLK/scratch-paint.git"
},
"dependencies": {
"@scratch/paper": "0.11.20180802201231",
"@scratch/paper": "0.11.20180806212106",
"classnames": "2.2.5",
"keymirror": "0.1.1",
"lodash.bindall": "4.4.0",

View file

@ -4,12 +4,10 @@ import bindAll from 'lodash.bindall';
import Box from '../box/box.jsx';
import {LOUPE_RADIUS} from '../../helper/tools/eye-dropper';
import {LOUPE_RADIUS, ZOOM_SCALE} from '../../helper/tools/eye-dropper';
import styles from './loupe.css';
const ZOOM_SCALE = 3;
class LoupeComponent extends React.Component {
constructor (props) {
super(props);
@ -21,38 +19,40 @@ class LoupeComponent extends React.Component {
this.draw();
}
draw () {
const boxSize = 6 / ZOOM_SCALE;
const boxLineWidth = 1 / ZOOM_SCALE;
const colorRingWidth = 15 / ZOOM_SCALE;
const boxSize = 5;
const boxLineWidth = 1;
const colorRingWidth = 15;
const loupeRadius = ZOOM_SCALE * LOUPE_RADIUS;
const loupeDiameter = loupeRadius * 2;
const color = this.props.colorInfo.color;
const ctx = this.canvas.getContext('2d');
this.canvas.width = ZOOM_SCALE * (LOUPE_RADIUS * 2);
this.canvas.height = ZOOM_SCALE * (LOUPE_RADIUS * 2);
this.canvas.width = loupeDiameter;
this.canvas.height = loupeDiameter;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, loupeDiameter, loupeDiameter);
// In order to scale the image data, must draw to a tmp canvas first
const tmpCanvas = document.createElement('canvas');
tmpCanvas.width = LOUPE_RADIUS * 2;
tmpCanvas.height = LOUPE_RADIUS * 2;
tmpCanvas.width = loupeDiameter;
tmpCanvas.height = loupeDiameter;
const tmpCtx = tmpCanvas.getContext('2d');
const imageData = tmpCtx.createImageData(
LOUPE_RADIUS * 2, LOUPE_RADIUS * 2
loupeDiameter, loupeDiameter
);
imageData.data.set(this.props.colorInfo.data);
tmpCtx.putImageData(imageData, 0, 0);
// Scale the loupe canvas and draw the zoomed image
ctx.save();
ctx.scale(ZOOM_SCALE, ZOOM_SCALE);
ctx.drawImage(tmpCanvas, 0, 0, LOUPE_RADIUS * 2, LOUPE_RADIUS * 2);
ctx.drawImage(tmpCanvas, 0, 0);
// Draw an outlined square at the cursor position (cursor is hidden)
ctx.lineWidth = boxLineWidth;
ctx.strokeStyle = 'black';
ctx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3]})`;
ctx.beginPath();
ctx.rect((20) - (boxSize / 2), (20) - (boxSize / 2), boxSize, boxSize);
ctx.rect(loupeRadius - (boxSize / 2), loupeRadius - (boxSize / 2), boxSize, boxSize);
ctx.fill();
ctx.stroke();
@ -60,10 +60,9 @@ class LoupeComponent extends React.Component {
ctx.strokeStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3]})`;
ctx.lineWidth = colorRingWidth;
ctx.beginPath();
ctx.moveTo(LOUPE_RADIUS * 2, LOUPE_RADIUS);
ctx.arc(LOUPE_RADIUS, LOUPE_RADIUS, LOUPE_RADIUS, 0, 2 * Math.PI);
ctx.moveTo(loupeDiameter, loupeDiameter);
ctx.arc(loupeRadius, loupeRadius, loupeRadius, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
}
setCanvas (element) {
this.canvas = element;
@ -74,6 +73,7 @@ class LoupeComponent extends React.Component {
pixelRatio,
...boxProps
} = this.props;
const loupeDiameter = ZOOM_SCALE * LOUPE_RADIUS * 2;
return (
<Box
{...boxProps}
@ -82,10 +82,10 @@ class LoupeComponent extends React.Component {
element="canvas"
height={LOUPE_RADIUS * 2}
style={{
top: (colorInfo.y / pixelRatio) - ((ZOOM_SCALE * (LOUPE_RADIUS * 2)) / 2),
left: (colorInfo.x / pixelRatio) - ((ZOOM_SCALE * (LOUPE_RADIUS * 2)) / 2),
width: (LOUPE_RADIUS * 2) * ZOOM_SCALE,
height: (LOUPE_RADIUS * 2) * ZOOM_SCALE
top: (colorInfo.y / pixelRatio) - (loupeDiameter / 2),
left: (colorInfo.x / pixelRatio) - (loupeDiameter / 2),
width: loupeDiameter,
height: loupeDiameter
}}
width={LOUPE_RADIUS * 2}
/>

View file

@ -121,7 +121,6 @@ $border-radius: 0.25rem;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
.canvas-controls {

View file

@ -340,7 +340,8 @@ class PaintEditor extends React.Component {
paper.project.view.pixelRatio,
paper.view.zoom,
paper.project.view.bounds.x,
paper.project.view.bounds.y
paper.project.view.bounds.y,
isBitmap(this.props.format)
);
this.eyeDropper.pickX = -1;
this.eyeDropper.pickY = -1;

View file

@ -50,7 +50,7 @@ const getRaster = function () {
return _getLayer('isRasterLayer').children[0];
};
const _getBackgroundGuideLayer = function () {
const getBackgroundGuideLayer = function () {
return _getLayer('isBackgroundGuideLayer');
};
@ -75,7 +75,7 @@ const getGuideLayer = function () {
* @return {object} an object of the removed layers, which should be passed to showGuideLayers to re-add them.
*/
const hideGuideLayers = function (includeRaster) {
const backgroundGuideLayer = _getBackgroundGuideLayer();
const backgroundGuideLayer = getBackgroundGuideLayer();
const guideLayer = getGuideLayer();
guideLayer.remove();
backgroundGuideLayer.remove();
@ -213,6 +213,7 @@ export {
hideGuideLayers,
showGuideLayers,
getGuideLayer,
getBackgroundGuideLayer,
clearRaster,
getRaster,
setupLayers

View file

@ -1,11 +1,36 @@
import paper from '@scratch/paper';
import {createCanvas, getRaster, getBackgroundGuideLayer} from '../layer';
const LOUPE_RADIUS = 20;
const ZOOM_SCALE = 3;
class EyeDropperTool extends paper.Tool {
constructor (canvas, width, height, pixelRatio, zoom, offsetX, offsetY) {
constructor (canvas, width, height, pixelRatio, zoom, offsetX, offsetY, isBitmap) {
super();
const layer = isBitmap ? getRaster().layer : paper.project.activeLayer;
const contentRaster3x = layer.rasterize(
72 * ZOOM_SCALE * paper.view.zoom, false /* insert */, paper.view.bounds);
const backgroundRaster3x = getBackgroundGuideLayer().rasterize(
72 * ZOOM_SCALE * paper.view.zoom, false /* insert */, paper.view.bounds);
// Canvas from which loupe is cut, shows art and grid
this.bufferCanvas = createCanvas(canvas.width * ZOOM_SCALE, canvas.height * ZOOM_SCALE);
const bufferCanvasContext = this.bufferCanvas.getContext('2d');
// Canvas to sample colors from; just the art
this.colorCanvas = createCanvas(canvas.width * ZOOM_SCALE, canvas.height * ZOOM_SCALE);
const colorCanvasContext = this.colorCanvas.getContext('2d');
backgroundRaster3x.onLoad = () => {
bufferCanvasContext.drawImage(backgroundRaster3x.canvas, 0, 0);
contentRaster3x.onLoad = () => {
colorCanvasContext.drawImage(contentRaster3x.canvas, 0, 0);
bufferCanvasContext.drawImage(this.colorCanvas, 0, 0);
this.bufferLoaded = true;
};
if (contentRaster3x.loaded) contentRaster3x.onLoad();
};
this.onMouseDown = this.handleMouseDown;
this.onMouseMove = this.handleMouseMove;
@ -21,23 +46,6 @@ class EyeDropperTool extends paper.Tool {
this.pickX = -1;
this.pickY = -1;
this.hideLoupe = true;
/*
Chrome 64 has a bug that makes it impossible to use getImageData directly
a 2d canvas. Until that is resolved, copy the canvas to a buffer canvas
and read the data from there.
https://github.com/LLK/scratch-paint/issues/276
*/
this.bufferLoaded = false;
this.bufferCanvas = document.createElement('canvas');
this.bufferCanvas.width = canvas.width;
this.bufferCanvas.height = canvas.height;
this.bufferImage = new Image();
this.bufferImage.onload = () => {
this.bufferCanvas.getContext('2d').drawImage(this.bufferImage, 0, 0);
this.bufferLoaded = true;
};
this.bufferImage.src = canvas.toDataURL();
}
handleMouseMove (event) {
// Set the pickX/Y for the color picker loop to pick up
@ -54,6 +62,11 @@ class EyeDropperTool extends paper.Tool {
if (!this.hideLoupe) {
const colorInfo = this.getColorInfo(this.pickX, this.pickY, this.hideLoupe);
if (!colorInfo) return;
if (colorInfo.color[3] === 0) {
// Alpha 0
this.colorString = null;
return;
}
const r = colorInfo.color[0];
const g = colorInfo.color[1];
const b = colorInfo.color[2];
@ -68,18 +81,21 @@ class EyeDropperTool extends paper.Tool {
}
}
getColorInfo (x, y, hideLoupe) {
const artX = x / this.pixelRatio;
const artY = y / this.pixelRatio;
if (!this.bufferLoaded) return null;
const ctx = this.bufferCanvas.getContext('2d');
const colors = ctx.getImageData(x, y, 1, 1);
const colorContext = this.colorCanvas.getContext('2d');
const bufferContext = this.bufferCanvas.getContext('2d');
const colors = colorContext.getImageData(artX * ZOOM_SCALE, artY * ZOOM_SCALE, 1, 1);
return {
x: x,
y: y,
color: colors.data,
data: ctx.getImageData(
x - LOUPE_RADIUS,
y - LOUPE_RADIUS,
LOUPE_RADIUS * 2,
LOUPE_RADIUS * 2
data: bufferContext.getImageData(
(artX * ZOOM_SCALE) - (LOUPE_RADIUS * ZOOM_SCALE),
(artY * ZOOM_SCALE) - (LOUPE_RADIUS * ZOOM_SCALE),
LOUPE_RADIUS * 2 * ZOOM_SCALE,
LOUPE_RADIUS * 2 * ZOOM_SCALE
).data,
hideLoupe: hideLoupe
};
@ -88,5 +104,6 @@ class EyeDropperTool extends paper.Tool {
export {
EyeDropperTool as default,
LOUPE_RADIUS
LOUPE_RADIUS,
ZOOM_SCALE
};