mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-23 05:52:42 -05:00
Move convert to bitmap into bitmap helper (#490)
This commit is contained in:
parent
a9ba5eac9b
commit
ebed37390d
2 changed files with 68 additions and 65 deletions
|
@ -7,13 +7,11 @@ import Formats from '../lib/format';
|
||||||
import Modes from '../lib/modes';
|
import Modes from '../lib/modes';
|
||||||
import log from '../log/log';
|
import log from '../log/log';
|
||||||
|
|
||||||
import {inlineSvgFonts} from 'scratch-svg-renderer';
|
import {convertToBitmap, convertToVector} from '../helper/bitmap';
|
||||||
|
|
||||||
import {trim} from '../helper/bitmap';
|
|
||||||
import {performSnapshot} from '../helper/undo';
|
import {performSnapshot} from '../helper/undo';
|
||||||
import {undoSnapshot, clearUndoState} from '../reducers/undo';
|
import {undoSnapshot, clearUndoState} from '../reducers/undo';
|
||||||
import {isGroup, ungroupItems} from '../helper/group';
|
import {isGroup, ungroupItems} from '../helper/group';
|
||||||
import {clearRaster, getRaster, setupLayers, hideGuideLayers, showGuideLayers} from '../helper/layer';
|
import {clearRaster, getRaster, setupLayers} from '../helper/layer';
|
||||||
import {deleteSelection, getSelectedLeafItems} from '../helper/selection';
|
import {deleteSelection, getSelectedLeafItems} from '../helper/selection';
|
||||||
import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items';
|
import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items';
|
||||||
import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT, pan, resetZoom, zoomOnFixedPoint} from '../helper/view';
|
import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT, pan, resetZoom, zoomOnFixedPoint} from '../helper/view';
|
||||||
|
@ -31,8 +29,6 @@ class PaperCanvas extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
'convertToBitmap',
|
|
||||||
'convertToVector',
|
|
||||||
'setCanvas',
|
'setCanvas',
|
||||||
'importSvg',
|
'importSvg',
|
||||||
'handleKeyDown',
|
'handleKeyDown',
|
||||||
|
@ -61,9 +57,9 @@ class PaperCanvas extends React.Component {
|
||||||
this.switchCostume(
|
this.switchCostume(
|
||||||
newProps.imageFormat, newProps.image, newProps.rotationCenterX, newProps.rotationCenterY);
|
newProps.imageFormat, newProps.image, newProps.rotationCenterX, newProps.rotationCenterY);
|
||||||
} else if (isVector(this.props.format) && newProps.format === Formats.BITMAP) {
|
} else if (isVector(this.props.format) && newProps.format === Formats.BITMAP) {
|
||||||
this.convertToBitmap();
|
convertToBitmap(this.props.clearSelectedItems, this.props.onUpdateImage);
|
||||||
} else if (isBitmap(this.props.format) && newProps.format === Formats.VECTOR) {
|
} else if (isBitmap(this.props.format) && newProps.format === Formats.VECTOR) {
|
||||||
this.convertToVector();
|
convertToVector(this.props.clearSelectedItems, this.props.onUpdateImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -82,60 +78,6 @@ class PaperCanvas extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convertToBitmap () {
|
|
||||||
// @todo if the active layer contains only rasters, drawing them directly to the raster layer
|
|
||||||
// would be more efficient.
|
|
||||||
|
|
||||||
// Export svg
|
|
||||||
const guideLayers = hideGuideLayers(true /* includeRaster */);
|
|
||||||
const bounds = paper.project.activeLayer.bounds;
|
|
||||||
const svg = paper.project.exportSVG({
|
|
||||||
bounds: 'content',
|
|
||||||
matrix: new paper.Matrix().translate(-bounds.x, -bounds.y)
|
|
||||||
});
|
|
||||||
showGuideLayers(guideLayers);
|
|
||||||
|
|
||||||
// Get rid of anti-aliasing
|
|
||||||
// @todo get crisp text?
|
|
||||||
svg.setAttribute('shape-rendering', 'crispEdges');
|
|
||||||
inlineSvgFonts(svg);
|
|
||||||
const svgString = (new XMLSerializer()).serializeToString(svg);
|
|
||||||
|
|
||||||
// Put anti-aliased SVG into image, and dump image back into canvas
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = () => {
|
|
||||||
if (img.width && img.height) {
|
|
||||||
getRaster().drawImage(
|
|
||||||
img,
|
|
||||||
new paper.Point(Math.floor(bounds.topLeft.x), Math.floor(bounds.topLeft.y)));
|
|
||||||
}
|
|
||||||
paper.project.activeLayer.removeChildren();
|
|
||||||
this.props.onUpdateImage();
|
|
||||||
};
|
|
||||||
img.onerror = () => {
|
|
||||||
// Fallback if browser does not support SVG data URIs in images.
|
|
||||||
// The problem with rasterize is that it will anti-alias.
|
|
||||||
const raster = paper.project.activeLayer.rasterize(72, false /* insert */);
|
|
||||||
raster.onLoad = () => {
|
|
||||||
if (raster.canvas.width && raster.canvas.height) {
|
|
||||||
getRaster().drawImage(raster.canvas, raster.bounds.topLeft);
|
|
||||||
}
|
|
||||||
paper.project.activeLayer.removeChildren();
|
|
||||||
this.props.onUpdateImage();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// Hash tags will break image loading without being encoded first
|
|
||||||
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgString)}`;
|
|
||||||
}
|
|
||||||
convertToVector () {
|
|
||||||
this.props.clearSelectedItems();
|
|
||||||
const trimmedRaster = trim(getRaster());
|
|
||||||
if (trimmedRaster) {
|
|
||||||
paper.project.activeLayer.addChild(trimmedRaster);
|
|
||||||
}
|
|
||||||
clearRaster();
|
|
||||||
this.props.onUpdateImage();
|
|
||||||
}
|
|
||||||
switchCostume (format, image, rotationCenterX, rotationCenterY) {
|
switchCostume (format, image, rotationCenterX, rotationCenterY) {
|
||||||
for (const layer of paper.project.layers) {
|
for (const layer of paper.project.layers) {
|
||||||
if (layer.data.isRasterLayer) {
|
if (layer.data.isRasterLayer) {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import paper from '@scratch/paper';
|
import paper from '@scratch/paper';
|
||||||
|
import {clearRaster, getRaster, hideGuideLayers, showGuideLayers} from '../helper/layer';
|
||||||
|
import {inlineSvgFonts} from 'scratch-svg-renderer';
|
||||||
|
|
||||||
const forEachLinePoint = function (point1, point2, callback) {
|
const forEachLinePoint = function (point1, point2, callback) {
|
||||||
// Bresenham line algorithm
|
// Bresenham line algorithm
|
||||||
|
@ -141,7 +143,7 @@ const getHitBounds = function (raster) {
|
||||||
return new paper.Rectangle(left, top, right - left, bottom - top);
|
return new paper.Rectangle(left, top, right - left, bottom - top);
|
||||||
};
|
};
|
||||||
|
|
||||||
const trim = function (raster) {
|
const trim_ = function (raster) {
|
||||||
const hitBounds = getHitBounds(raster);
|
const hitBounds = getHitBounds(raster);
|
||||||
if (hitBounds.width && hitBounds.height) {
|
if (hitBounds.width && hitBounds.height) {
|
||||||
return raster.getSubRaster(getHitBounds(raster));
|
return raster.getSubRaster(getHitBounds(raster));
|
||||||
|
@ -149,10 +151,69 @@ const trim = function (raster) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const convertToBitmap = function (clearSelectedItems, onUpdateImage) {
|
||||||
|
// @todo if the active layer contains only rasters, drawing them directly to the raster layer
|
||||||
|
// would be more efficient.
|
||||||
|
|
||||||
|
clearSelectedItems();
|
||||||
|
|
||||||
|
// Export svg
|
||||||
|
const guideLayers = hideGuideLayers(true /* includeRaster */);
|
||||||
|
const bounds = paper.project.activeLayer.bounds;
|
||||||
|
const svg = paper.project.exportSVG({
|
||||||
|
bounds: 'content',
|
||||||
|
matrix: new paper.Matrix().translate(-bounds.x, -bounds.y)
|
||||||
|
});
|
||||||
|
showGuideLayers(guideLayers);
|
||||||
|
|
||||||
|
// Get rid of anti-aliasing
|
||||||
|
// @todo get crisp text?
|
||||||
|
svg.setAttribute('shape-rendering', 'crispEdges');
|
||||||
|
inlineSvgFonts(svg);
|
||||||
|
const svgString = (new XMLSerializer()).serializeToString(svg);
|
||||||
|
|
||||||
|
// Put anti-aliased SVG into image, and dump image back into canvas
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
if (img.width && img.height) {
|
||||||
|
getRaster().drawImage(
|
||||||
|
img,
|
||||||
|
new paper.Point(Math.floor(bounds.topLeft.x), Math.floor(bounds.topLeft.y)));
|
||||||
|
}
|
||||||
|
paper.project.activeLayer.removeChildren();
|
||||||
|
onUpdateImage();
|
||||||
|
};
|
||||||
|
img.onerror = () => {
|
||||||
|
// Fallback if browser does not support SVG data URIs in images.
|
||||||
|
// The problem with rasterize is that it will anti-alias.
|
||||||
|
const raster = paper.project.activeLayer.rasterize(72, false /* insert */);
|
||||||
|
raster.onLoad = () => {
|
||||||
|
if (raster.canvas.width && raster.canvas.height) {
|
||||||
|
getRaster().drawImage(raster.canvas, raster.bounds.topLeft);
|
||||||
|
}
|
||||||
|
paper.project.activeLayer.removeChildren();
|
||||||
|
onUpdateImage();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Hash tags will break image loading without being encoded first
|
||||||
|
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgString)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const convertToVector = function (clearSelectedItems, onUpdateImage) {
|
||||||
|
clearSelectedItems();
|
||||||
|
const trimmedRaster = trim_(getRaster());
|
||||||
|
if (trimmedRaster) {
|
||||||
|
paper.project.activeLayer.addChild(trimmedRaster);
|
||||||
|
}
|
||||||
|
clearRaster();
|
||||||
|
onUpdateImage();
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
convertToBitmap,
|
||||||
|
convertToVector,
|
||||||
getBrushMark,
|
getBrushMark,
|
||||||
getHitBounds,
|
getHitBounds,
|
||||||
fillEllipse,
|
fillEllipse,
|
||||||
forEachLinePoint,
|
forEachLinePoint
|
||||||
trim
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue