2011-03-06 19:50:44 -05:00
|
|
|
/*
|
2013-01-28 21:03:27 -05:00
|
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
2011-03-07 20:41:50 -05:00
|
|
|
* http://paperjs.org/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2013-01-28 21:03:27 -05:00
|
|
|
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
|
2011-03-06 19:50:44 -05:00
|
|
|
* http://lehni.org/ & http://jonathanpuckey.com/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-07-01 06:17:45 -04:00
|
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
|
|
*
|
2011-03-07 20:41:50 -05:00
|
|
|
* All rights reserved.
|
2011-03-06 19:50:44 -05:00
|
|
|
*/
|
|
|
|
|
2011-06-22 18:56:05 -04:00
|
|
|
/**
|
|
|
|
* @name Raster
|
2011-07-01 05:26:51 -04:00
|
|
|
*
|
2011-06-22 18:56:05 -04:00
|
|
|
* @class The Raster item represents an image in a Paper.js project.
|
2011-07-01 05:26:51 -04:00
|
|
|
*
|
|
|
|
* @extends PlacedItem
|
2011-06-22 18:56:05 -04:00
|
|
|
*/
|
2011-07-01 05:26:51 -04:00
|
|
|
var Raster = this.Raster = PlacedItem.extend(/** @lends Raster# */{
|
2012-11-04 01:43:18 -05:00
|
|
|
_type: 'raster',
|
2011-11-24 09:44:26 -05:00
|
|
|
// Raster doesn't make the distinction between the different bounds,
|
2011-11-24 10:03:05 -05:00
|
|
|
// so use the same name for all of them
|
2012-12-15 11:19:10 -05:00
|
|
|
_boundsGetter: 'getBounds',
|
2011-11-24 09:44:26 -05:00
|
|
|
|
2012-12-23 19:12:41 -05:00
|
|
|
// TODO: Implement type, width, height.
|
2011-06-01 05:49:43 -04:00
|
|
|
// TODO: Have PlacedSymbol & Raster inherit from a shared class?
|
|
|
|
// DOCS: Document Raster constructor.
|
2011-05-23 10:09:04 -04:00
|
|
|
/**
|
|
|
|
* Creates a new raster item and places it in the active layer.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @param {HTMLImageElement|Canvas|string} [object]
|
|
|
|
*/
|
2012-12-25 16:12:25 -05:00
|
|
|
initialize: function(arg0, arg1) {
|
|
|
|
// Support two forms of item initialization: Passing one object literal
|
|
|
|
// describing all the different properties to be set, or an image (arg0)
|
|
|
|
// and a point where it should be placed (arg1).
|
|
|
|
this.base(arg1 !== undefined && Point.read(arguments, 1));
|
|
|
|
// If we can handle setting properties through object literal, we're all
|
|
|
|
// set. Otherwise we need to check the type of arg0:
|
2012-12-26 18:52:09 -05:00
|
|
|
if (!this._setProperties(arg0)) {
|
2012-12-25 16:12:25 -05:00
|
|
|
if (arg0.getContext) {
|
|
|
|
this.setCanvas(arg0);
|
|
|
|
} else if (typeof arg0 === 'string') {
|
2013-02-11 19:34:31 -05:00
|
|
|
// Both data-urls and normal urls are supported here!
|
2012-12-25 16:12:25 -05:00
|
|
|
this.setSource(arg0);
|
|
|
|
} else {
|
|
|
|
this.setImage(arg0);
|
|
|
|
}
|
2011-02-21 12:43:56 -05:00
|
|
|
}
|
|
|
|
},
|
2011-02-23 19:28:11 -05:00
|
|
|
|
2011-05-19 16:56:49 -04:00
|
|
|
clone: function() {
|
2011-05-21 06:50:02 -04:00
|
|
|
var image = this._image;
|
|
|
|
if (!image) {
|
|
|
|
// If the Raster contains a Canvas object, we need to create
|
|
|
|
// a new one and draw this raster's canvas on it.
|
|
|
|
image = CanvasProvider.getCanvas(this._size);
|
|
|
|
image.getContext('2d').drawImage(this._canvas, 0, 0);
|
|
|
|
}
|
2011-05-21 12:02:09 -04:00
|
|
|
var copy = new Raster(image);
|
|
|
|
return this._clone(copy);
|
2011-05-19 16:56:49 -04:00
|
|
|
},
|
|
|
|
|
2011-02-23 19:28:11 -05:00
|
|
|
/**
|
2011-05-23 10:09:04 -04:00
|
|
|
* The size of the raster in pixels.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @type Size
|
|
|
|
* @bean
|
|
|
|
*/
|
2011-02-23 19:28:11 -05:00
|
|
|
getSize: function() {
|
|
|
|
return this._size;
|
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-02-23 19:28:11 -05:00
|
|
|
setSize: function() {
|
2012-12-03 00:13:03 -05:00
|
|
|
var size = Size.read(arguments);
|
|
|
|
if (!this._size.equals(size)) {
|
2011-03-08 07:55:34 -05:00
|
|
|
// Get reference to image before changing canvas
|
2012-12-03 00:13:03 -05:00
|
|
|
var image = this.getImage();
|
|
|
|
// Setting canvas internally sets _size
|
|
|
|
this.setCanvas(CanvasProvider.getCanvas(size));
|
|
|
|
// Draw image back onto new canvas
|
|
|
|
this.getContext(true).drawImage(image, 0, 0, size.width, size.height);
|
|
|
|
}
|
2011-02-23 19:28:11 -05:00
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-02-21 12:43:56 -05:00
|
|
|
/**
|
|
|
|
* The width of the raster in pixels.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 14:15:15 -04:00
|
|
|
* @type Number
|
2011-05-23 10:09:04 -04:00
|
|
|
* @bean
|
2011-02-21 12:43:56 -05:00
|
|
|
*/
|
|
|
|
getWidth: function() {
|
2011-02-23 19:28:11 -05:00
|
|
|
return this._size.width;
|
2011-02-21 12:43:56 -05:00
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-02-21 12:43:56 -05:00
|
|
|
/**
|
|
|
|
* The height of the raster in pixels.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 14:15:15 -04:00
|
|
|
* @type Number
|
2011-05-23 10:09:04 -04:00
|
|
|
* @bean
|
2011-02-21 12:43:56 -05:00
|
|
|
*/
|
|
|
|
getHeight: function() {
|
2011-02-23 19:28:11 -05:00
|
|
|
return this._size.height;
|
2011-02-21 12:43:56 -05:00
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2012-10-10 23:11:11 -04:00
|
|
|
isEmpty: function() {
|
|
|
|
return this._size.width == 0 && this._size.height == 0;
|
|
|
|
},
|
|
|
|
|
2011-02-24 07:52:27 -05:00
|
|
|
/**
|
2011-06-08 13:47:34 -04:00
|
|
|
* Pixels per inch of the raster at its current size.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @type Size
|
|
|
|
* @bean
|
2011-02-24 07:52:27 -05:00
|
|
|
*/
|
|
|
|
getPpi: function() {
|
2011-07-01 05:32:09 -04:00
|
|
|
var matrix = this._matrix,
|
2011-03-08 07:55:34 -05:00
|
|
|
orig = new Point(0, 0).transform(matrix),
|
|
|
|
u = new Point(1, 0).transform(matrix).subtract(orig),
|
|
|
|
v = new Point(0, 1).transform(matrix).subtract(orig);
|
2011-11-29 11:11:15 -05:00
|
|
|
return Size.create(
|
2011-03-04 21:40:38 -05:00
|
|
|
72 / u.getLength(),
|
|
|
|
72 / v.getLength()
|
2011-02-24 07:52:27 -05:00
|
|
|
);
|
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-05-23 10:09:04 -04:00
|
|
|
/**
|
|
|
|
* The Canvas 2d drawing context of the raster.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @type Context
|
|
|
|
* @bean
|
|
|
|
*/
|
2013-02-09 12:44:25 -05:00
|
|
|
getContext: function(/* modify */) {
|
2011-06-20 15:13:24 -04:00
|
|
|
if (!this._context)
|
2011-03-04 21:40:38 -05:00
|
|
|
this._context = this.getCanvas().getContext('2d');
|
2011-06-20 15:13:24 -04:00
|
|
|
// Support a hidden parameter that indicates if the context will be used
|
|
|
|
// to modify the Raster object. We can notify such changes ahead since
|
|
|
|
// they are only used afterwards for redrawing.
|
2013-02-09 12:44:25 -05:00
|
|
|
if (arguments[0]) {
|
|
|
|
// Also set _image to null since the Raster stops representing it.
|
|
|
|
// NOTE: This should theoretically be in our own _changed() handler
|
|
|
|
// for ChangeFlag.PIXELS, but since it's only happening in one place
|
|
|
|
// this is fine:
|
|
|
|
this._image = null;
|
2012-11-05 21:11:44 -05:00
|
|
|
this._changed(/*#=*/ Change.PIXELS);
|
2013-02-09 12:44:25 -05:00
|
|
|
}
|
2011-03-04 21:40:38 -05:00
|
|
|
return this._context;
|
|
|
|
},
|
|
|
|
|
|
|
|
setContext: function(context) {
|
|
|
|
this._context = context;
|
|
|
|
},
|
|
|
|
|
2011-03-04 20:26:12 -05:00
|
|
|
getCanvas: function() {
|
|
|
|
if (!this._canvas) {
|
2013-02-11 19:34:31 -05:00
|
|
|
var canvas = CanvasProvider.getCanvas(this._size);
|
|
|
|
// Since drawimage images into canvases might fail based on security
|
|
|
|
// policies, wrap the call in try-catch and only set _canvas if we
|
|
|
|
// succeeded.
|
|
|
|
try {
|
|
|
|
if (this._image)
|
|
|
|
this.getContext(true).drawImage(this._image, 0, 0);
|
|
|
|
this._canvas = canvas;
|
|
|
|
} catch (e) {
|
|
|
|
CanvasProvider.returnCanvas(canvas);
|
|
|
|
}
|
2011-03-04 20:26:12 -05:00
|
|
|
}
|
|
|
|
return this._canvas;
|
|
|
|
},
|
|
|
|
|
|
|
|
setCanvas: function(canvas) {
|
|
|
|
if (this._canvas)
|
|
|
|
CanvasProvider.returnCanvas(this._canvas);
|
|
|
|
this._canvas = canvas;
|
2011-11-29 11:11:15 -05:00
|
|
|
this._size = Size.create(canvas.width, canvas.height);
|
2011-03-04 20:26:12 -05:00
|
|
|
this._image = null;
|
|
|
|
this._context = null;
|
2012-11-05 21:11:44 -05:00
|
|
|
this._changed(/*#=*/ Change.GEOMETRY | /*#=*/ Change.PIXELS);
|
2011-03-04 20:26:12 -05:00
|
|
|
},
|
|
|
|
|
2011-05-23 10:09:04 -04:00
|
|
|
/**
|
2013-02-11 19:34:59 -05:00
|
|
|
* The HTMLImageElement of the raster, if one is associated.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @type HTMLImageElement|Canvas
|
|
|
|
* @bean
|
|
|
|
*/
|
2011-03-04 20:26:12 -05:00
|
|
|
getImage: function() {
|
2013-02-11 19:34:59 -05:00
|
|
|
return this._image;
|
2011-03-04 20:26:12 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
setImage: function(image) {
|
|
|
|
if (this._canvas)
|
|
|
|
CanvasProvider.returnCanvas(this._canvas);
|
|
|
|
this._image = image;
|
2011-08-21 10:38:06 -04:00
|
|
|
/*#*/ if (options.browser) {
|
2011-11-29 11:11:15 -05:00
|
|
|
this._size = Size.create(image.naturalWidth, image.naturalHeight);
|
2011-08-21 10:38:06 -04:00
|
|
|
/*#*/ } else if (options.server) {
|
2011-11-29 11:11:15 -05:00
|
|
|
this._size = Size.create(image.width, image.height);
|
2011-08-21 10:38:06 -04:00
|
|
|
/*#*/ } // options.server
|
2011-03-04 20:26:12 -05:00
|
|
|
this._canvas = null;
|
|
|
|
this._context = null;
|
2012-11-05 21:11:44 -05:00
|
|
|
this._changed(/*#=*/ Change.GEOMETRY);
|
2011-03-04 20:26:12 -05:00
|
|
|
},
|
|
|
|
|
2012-12-23 19:12:41 -05:00
|
|
|
getSource: function() {
|
2013-02-11 19:34:31 -05:00
|
|
|
var img = this.getImage();
|
|
|
|
return img && img.src || null;
|
2012-12-23 19:12:41 -05:00
|
|
|
},
|
|
|
|
|
2013-02-11 19:35:46 -05:00
|
|
|
// DOCS: Document Raster#setSource
|
|
|
|
// NOTE: Both data-urls and normal urls are supported in setSource!
|
2012-12-23 19:12:41 -05:00
|
|
|
setSource: function(src) {
|
|
|
|
/*#*/ if (options.browser) {
|
|
|
|
var that = this,
|
|
|
|
// src can be an URL or a DOM ID to load the image from
|
|
|
|
image = document.getElementById(src) || new Image();
|
2013-02-11 19:35:46 -05:00
|
|
|
function loaded() {
|
|
|
|
that.fire('load');
|
|
|
|
if (that._project.view)
|
|
|
|
that._project.view.draw(true);
|
|
|
|
}
|
2012-12-23 19:12:41 -05:00
|
|
|
// Trigger the onLoad event on the image once it's loaded
|
|
|
|
DomEvent.add(image, {
|
|
|
|
load: function() {
|
|
|
|
that.setImage(image);
|
2013-02-11 19:35:46 -05:00
|
|
|
loaded();
|
2012-12-23 19:12:41 -05:00
|
|
|
}
|
|
|
|
});
|
2013-02-11 19:35:46 -05:00
|
|
|
if (image.width && image.height) {
|
|
|
|
// Fire load event delayed, so behavior is the same as when it's
|
|
|
|
// actually loaded and we give the code time to install event
|
|
|
|
setTimeout(loaded, 0);
|
|
|
|
} else if (!image.src) {
|
2012-12-23 19:12:41 -05:00
|
|
|
image.src = src;
|
2013-02-11 19:35:46 -05:00
|
|
|
}
|
2012-12-23 19:12:41 -05:00
|
|
|
/*#*/ } else if (options.server) {
|
|
|
|
// If we're running on the server and it's a string,
|
|
|
|
// load it from disk:
|
|
|
|
// TODO: load images async, calling setImage once loaded as above
|
|
|
|
var image = new Image();
|
|
|
|
image.src = fs.readFileSync(src);
|
|
|
|
/*#*/ } // options.server
|
|
|
|
this.setImage(image);
|
|
|
|
},
|
|
|
|
|
2011-05-23 10:09:04 -04:00
|
|
|
// DOCS: document Raster#getSubImage
|
|
|
|
/**
|
2011-05-23 10:19:37 -04:00
|
|
|
* @param {Rectangle} rect the boundaries of the sub image in pixel
|
|
|
|
* coordinates
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @return {Canvas}
|
|
|
|
*/
|
2011-03-13 13:31:00 -04:00
|
|
|
getSubImage: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
2011-04-26 10:39:16 -04:00
|
|
|
var canvas = CanvasProvider.getCanvas(rect.getSize());
|
|
|
|
canvas.getContext('2d').drawImage(this.getCanvas(), rect.x, rect.y,
|
2011-03-05 09:17:32 -05:00
|
|
|
canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
|
2011-02-24 07:52:27 -05:00
|
|
|
return canvas;
|
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2013-02-09 12:44:25 -05:00
|
|
|
toDataURL: function() {
|
2013-02-11 19:34:31 -05:00
|
|
|
// See if the linked image is base64 encoded already, if so reuse it,
|
|
|
|
// otherwise try using canvas.toDataUrl()
|
2013-02-09 12:44:25 -05:00
|
|
|
var src = this._image && this._image.src;
|
2013-02-11 19:34:31 -05:00
|
|
|
if (/^data:/.test(src))
|
|
|
|
return src;
|
|
|
|
var canvas = this.getCanvas();
|
|
|
|
return canvas ? canvas.toDataURL() : null;
|
2013-02-09 12:44:25 -05:00
|
|
|
},
|
|
|
|
|
2011-05-23 10:09:04 -04:00
|
|
|
/**
|
2011-05-23 10:19:37 -04:00
|
|
|
* Draws an image on the raster.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @param {HTMLImageELement|Canvas} image
|
2011-05-23 10:19:37 -04:00
|
|
|
* @param {Point} point the offset of the image as a point in pixel
|
|
|
|
* coordinates
|
2011-05-23 10:09:04 -04:00
|
|
|
*/
|
2011-03-04 20:26:12 -05:00
|
|
|
drawImage: function(image, point) {
|
2011-03-13 13:31:00 -04:00
|
|
|
point = Point.read(arguments, 1);
|
2011-06-20 15:13:24 -04:00
|
|
|
this.getContext(true).drawImage(image, point.x, point.y);
|
2011-02-24 07:52:27 -05:00
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-05-19 09:43:23 -04:00
|
|
|
/**
|
|
|
|
* Calculates the average color of the image within the given path,
|
|
|
|
* rectangle or point. This can be used for creating raster image
|
|
|
|
* effects.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 10:09:04 -04:00
|
|
|
* @param {Path|Rectangle|Point} object
|
2011-11-10 13:16:34 -05:00
|
|
|
* @return {RgbColor} the average color contained in the area covered by the
|
2011-05-19 09:43:23 -04:00
|
|
|
* specified path, rectangle or point.
|
|
|
|
*/
|
|
|
|
getAverageColor: function(object) {
|
|
|
|
var bounds, path;
|
2011-12-27 14:39:46 -05:00
|
|
|
if (!object) {
|
|
|
|
bounds = this.getBounds();
|
|
|
|
} else if (object instanceof PathItem) {
|
2011-06-01 05:49:43 -04:00
|
|
|
// TODO: What if the path is smaller than 1 px?
|
|
|
|
// TODO: How about rounding of bounds.size?
|
2011-05-19 09:43:23 -04:00
|
|
|
path = object;
|
|
|
|
bounds = object.getBounds();
|
|
|
|
} else if (object.width) {
|
|
|
|
bounds = new Rectangle(object);
|
|
|
|
} else if (object.x) {
|
2011-11-29 11:19:15 -05:00
|
|
|
// Create a rectangle of 1px size around the specified coordinates
|
2011-05-19 09:43:23 -04:00
|
|
|
bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1);
|
|
|
|
}
|
2011-05-19 13:51:13 -04:00
|
|
|
// Use a sample size of max 32 x 32 pixels, into which the path is
|
|
|
|
// scaled as a clipping path, and then the actual image is drawn in and
|
|
|
|
// sampled.
|
2011-05-19 13:47:49 -04:00
|
|
|
var sampleSize = 32,
|
|
|
|
width = Math.min(bounds.width, sampleSize),
|
|
|
|
height = Math.min(bounds.height, sampleSize);
|
2011-05-19 13:51:13 -04:00
|
|
|
// Reuse the same sample context for speed. Memory consumption is low
|
|
|
|
// since it's only 32 x 32 pixels.
|
2011-05-19 13:47:49 -04:00
|
|
|
var ctx = Raster._sampleContext;
|
|
|
|
if (!ctx) {
|
2011-05-19 09:43:23 -04:00
|
|
|
ctx = Raster._sampleContext = CanvasProvider.getCanvas(
|
2011-12-27 13:55:55 -05:00
|
|
|
new Size(sampleSize)).getContext('2d');
|
2011-05-19 09:43:23 -04:00
|
|
|
} else {
|
|
|
|
// Clear the sample canvas:
|
|
|
|
ctx.clearRect(0, 0, sampleSize, sampleSize);
|
|
|
|
}
|
|
|
|
ctx.save();
|
2011-05-19 13:51:13 -04:00
|
|
|
// Scale the context so that the bounds ends up at the given sample size
|
2011-05-19 13:47:49 -04:00
|
|
|
ctx.scale(width / bounds.width, height / bounds.height);
|
|
|
|
ctx.translate(-bounds.x, -bounds.y);
|
2011-05-19 09:43:23 -04:00
|
|
|
// If a path was passed, draw it as a clipping mask:
|
2011-06-04 10:28:06 -04:00
|
|
|
if (path)
|
|
|
|
path.draw(ctx, { clip: true });
|
2011-05-19 13:51:13 -04:00
|
|
|
// Now draw the image clipped into it.
|
2011-07-01 05:32:09 -04:00
|
|
|
this._matrix.applyToContext(ctx);
|
2011-05-19 09:43:23 -04:00
|
|
|
ctx.drawImage(this._canvas || this._image,
|
|
|
|
-this._size.width / 2, -this._size.height / 2);
|
|
|
|
ctx.restore();
|
2011-05-19 13:51:13 -04:00
|
|
|
// Get pixel data from the context and calculate the average color value
|
|
|
|
// from it, taking alpha into account.
|
2011-05-19 09:43:23 -04:00
|
|
|
var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width),
|
|
|
|
Math.ceil(height)).data,
|
|
|
|
channels = [0, 0, 0],
|
|
|
|
total = 0;
|
|
|
|
for (var i = 0, l = pixels.length; i < l; i += 4) {
|
|
|
|
var alpha = pixels[i + 3];
|
|
|
|
total += alpha;
|
|
|
|
alpha /= 255;
|
|
|
|
channels[0] += pixels[i] * alpha;
|
|
|
|
channels[1] += pixels[i + 1] * alpha;
|
|
|
|
channels[2] += pixels[i + 2] * alpha;
|
|
|
|
}
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
|
|
channels[i] /= total;
|
|
|
|
return total ? Color.read(channels) : null;
|
|
|
|
},
|
|
|
|
|
2011-05-27 07:28:13 -04:00
|
|
|
/**
|
|
|
|
* {@grouptitle Pixels}
|
|
|
|
* Gets the color of a pixel in the raster.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:17:35 -04:00
|
|
|
* @name Raster#getPixel
|
2011-05-27 07:28:13 -04:00
|
|
|
* @function
|
|
|
|
* @param x the x offset of the pixel in pixel coordinates
|
|
|
|
* @param y the y offset of the pixel in pixel coordinates
|
2011-11-10 13:16:34 -05:00
|
|
|
* @return {RgbColor} the color of the pixel
|
2011-05-27 07:28:13 -04:00
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Gets the color of a pixel in the raster.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-06-16 14:26:50 -04:00
|
|
|
* @name Raster#getPixel
|
|
|
|
* @function
|
2011-05-27 07:28:13 -04:00
|
|
|
* @param point the offset of the pixel as a point in pixel coordinates
|
2011-11-10 13:16:34 -05:00
|
|
|
* @return {RgbColor} the color of the pixel
|
2011-05-27 07:28:13 -04:00
|
|
|
*/
|
|
|
|
getPixel: function(point) {
|
|
|
|
point = Point.read(arguments);
|
|
|
|
var pixels = this.getContext().getImageData(point.x, point.y, 1, 1).data,
|
|
|
|
channels = new Array(4);
|
|
|
|
for (var i = 0; i < 4; i++)
|
|
|
|
channels[i] = pixels[i] / 255;
|
2011-11-10 13:16:34 -05:00
|
|
|
return RgbColor.read(channels);
|
2011-05-27 07:28:13 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the color of the specified pixel to the specified color.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:17:35 -04:00
|
|
|
* @name Raster#setPixel
|
2011-05-27 07:28:13 -04:00
|
|
|
* @function
|
|
|
|
* @param x the x offset of the pixel in pixel coordinates
|
|
|
|
* @param y the y offset of the pixel in pixel coordinates
|
|
|
|
* @param color the color that the pixel will be set to
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Sets the color of the specified pixel to the specified color.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-06-16 14:26:50 -04:00
|
|
|
* @name Raster#setPixel
|
|
|
|
* @function
|
2011-05-27 07:28:13 -04:00
|
|
|
* @param point the offset of the pixel as a point in pixel coordinates
|
|
|
|
* @param color the color that the pixel will be set to
|
|
|
|
*/
|
|
|
|
setPixel: function(point, color) {
|
2012-10-18 17:24:15 -04:00
|
|
|
var _point = Point.read(arguments),
|
|
|
|
_color = Color.read(arguments);
|
2011-06-20 15:13:24 -04:00
|
|
|
var ctx = this.getContext(true),
|
2011-05-27 07:28:13 -04:00
|
|
|
imageData = ctx.createImageData(1, 1),
|
|
|
|
alpha = color.getAlpha();
|
2012-10-18 17:24:15 -04:00
|
|
|
imageData.data[0] = _color.getRed() * 255;
|
|
|
|
imageData.data[1] = _color.getGreen() * 255;
|
|
|
|
imageData.data[2] = _color.getBlue() * 255;
|
2011-05-27 07:28:13 -04:00
|
|
|
imageData.data[3] = alpha != null ? alpha * 255 : 255;
|
2012-10-18 17:24:15 -04:00
|
|
|
ctx.putImageData(imageData, _point.x, _point.y);
|
2011-05-27 07:28:13 -04:00
|
|
|
},
|
|
|
|
|
2011-05-23 10:19:37 -04:00
|
|
|
// DOCS: document Raster#createData
|
|
|
|
/**
|
2011-05-27 07:28:13 -04:00
|
|
|
* {@grouptitle Image Data}
|
2011-05-23 10:19:37 -04:00
|
|
|
* @param {Size} size
|
|
|
|
* @return {ImageData}
|
|
|
|
*/
|
2011-03-09 13:17:12 -05:00
|
|
|
createData: function(size) {
|
|
|
|
size = Size.read(arguments);
|
|
|
|
return this.getContext().createImageData(size.width, size.height);
|
|
|
|
},
|
|
|
|
|
2011-07-01 05:26:51 -04:00
|
|
|
// TODO: Rename to #get/setImageData, as it will conflict with Item#getData
|
2011-05-23 10:19:37 -04:00
|
|
|
// DOCS: document Raster#getData
|
|
|
|
/**
|
|
|
|
* @param {Rectangle} rect
|
|
|
|
* @return {ImageData}
|
|
|
|
*/
|
2011-03-13 13:31:00 -04:00
|
|
|
getData: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
2011-04-26 10:39:16 -04:00
|
|
|
if (rect.isEmpty())
|
|
|
|
rect = new Rectangle(this.getSize());
|
|
|
|
return this.getContext().getImageData(rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
2011-03-09 13:17:12 -05:00
|
|
|
},
|
|
|
|
|
2011-05-23 10:19:37 -04:00
|
|
|
// DOCS: document Raster#setData
|
|
|
|
/**
|
|
|
|
* @param {ImageData} data
|
|
|
|
* @param {Point} point
|
|
|
|
* @return {ImageData}
|
|
|
|
*/
|
2011-03-13 13:31:00 -04:00
|
|
|
setData: function(data, point) {
|
|
|
|
point = Point.read(arguments, 1);
|
2011-06-20 15:13:24 -04:00
|
|
|
this.getContext(true).putImageData(data, point.x, point.y);
|
2011-03-09 13:17:12 -05:00
|
|
|
},
|
|
|
|
|
2012-12-15 11:19:10 -05:00
|
|
|
_getBounds: function(getter, matrix) {
|
2011-11-26 04:39:51 -05:00
|
|
|
var rect = new Rectangle(this._size).setCenter(0, 0);
|
|
|
|
return matrix ? matrix._transformBounds(rect) : rect;
|
2011-07-04 13:45:53 -04:00
|
|
|
},
|
|
|
|
|
2011-11-11 09:00:53 -05:00
|
|
|
_hitTest: function(point, options) {
|
2011-12-24 18:19:44 -05:00
|
|
|
if (point.isInside(this._getBounds())) {
|
2011-11-11 09:00:53 -05:00
|
|
|
var that = this;
|
|
|
|
return new HitResult('pixel', that, {
|
|
|
|
offset: point.add(that._size.divide(2)).round(),
|
2012-09-30 17:07:27 -04:00
|
|
|
// Inject as Bootstrap accessor, so #toString renders well too
|
|
|
|
color: {
|
|
|
|
get: function() {
|
|
|
|
return that.getPixel(this.offset);
|
|
|
|
}
|
2011-11-11 09:00:53 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-03-03 07:19:43 -05:00
|
|
|
draw: function(ctx, param) {
|
2013-02-11 19:34:31 -05:00
|
|
|
var img = this._canvas || this._image;
|
|
|
|
if (img)
|
|
|
|
ctx.drawImage(img, -this._size.width / 2, -this._size.height / 2);
|
2011-12-20 05:42:00 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
drawSelected: function(ctx, matrix) {
|
|
|
|
Item.drawSelectedBounds(new Rectangle(this._size).setCenter(0, 0), ctx,
|
|
|
|
matrix);
|
2011-02-21 12:43:56 -05:00
|
|
|
}
|
2011-03-03 11:32:55 -05:00
|
|
|
});
|