Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changed to dataurl export #3314

Merged
merged 2 commits into from
Oct 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 123 additions & 216 deletions src/mixins/canvas_dataurl_exporter.mixin.js
Original file line number Diff line number Diff line change
@@ -1,217 +1,124 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {

/**
* Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately
* @param {Object} [options] Options object
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
* @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
* @param {Number} [options.multiplier=1] Multiplier to scale by
* @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
* @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}
* @example <caption>Generate jpeg dataURL with lower quality</caption>
* var dataURL = canvas.toDataURL({
* format: 'jpeg',
* quality: 0.8
* });
* @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>
* var dataURL = canvas.toDataURL({
* format: 'png',
* left: 100,
* top: 100,
* width: 200,
* height: 200
* });
* @example <caption>Generate double scaled png dataURL</caption>
* var dataURL = canvas.toDataURL({
* format: 'png',
* multiplier: 2
* });
*/
toDataURL: function (options) {
options || (options = { });

var format = options.format || 'png',
quality = options.quality || 1,
multiplier = options.multiplier || 1,
cropping = {
left: options.left,
top: options.top,
width: options.width,
height: options.height
};

if (this._isRetinaScaling()) {
multiplier *= fabric.devicePixelRatio;
}

if (multiplier !== 1) {
(function () {

var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality');

fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {

/**
* Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately
* @param {Object} [options] Options object
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
* @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
* @param {Number} [options.multiplier=1] Multiplier to scale by
* @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
* @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}
* @example <caption>Generate jpeg dataURL with lower quality</caption>
* var dataURL = canvas.toDataURL({
* format: 'jpeg',
* quality: 0.8
* });
* @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>
* var dataURL = canvas.toDataURL({
* format: 'png',
* left: 100,
* top: 100,
* width: 200,
* height: 200
* });
* @example <caption>Generate double scaled png dataURL</caption>
* var dataURL = canvas.toDataURL({
* format: 'png',
* multiplier: 2
* });
*/
toDataURL: function (options) {
options || (options = { });

var format = options.format || 'png',
quality = options.quality || 1,
multiplier = options.multiplier || 1,
cropping = {
left: options.left || 0,
top: options.top || 0,
width: options.width || 0,
height: options.height || 0,
};
return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier);
}
else {
return this.__toDataURL(format, quality, cropping);
}
},

/**
* @private
*/
__toDataURL: function(format, quality, cropping) {

this.renderAll();

var canvasEl = this.contextContainer.canvas,
croppedCanvasEl = this.__getCroppedCanvas(canvasEl, cropping);

// to avoid common confusion https://github.com/kangax/fabric.js/issues/806
if (format === 'jpg') {
format = 'jpeg';
}

var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))
? (croppedCanvasEl || canvasEl).toDataURL('image/' + format, quality)
: (croppedCanvasEl || canvasEl).toDataURL('image/' + format);

if (croppedCanvasEl) {
croppedCanvasEl = null;
}

return data;
},

/**
* @private
*/
__getCroppedCanvas: function(canvasEl, cropping) {

var croppedCanvasEl,
croppedCtx,
shouldCrop = 'left' in cropping ||
'top' in cropping ||
'width' in cropping ||
'height' in cropping;

if (shouldCrop) {

croppedCanvasEl = fabric.util.createCanvasElement();
croppedCtx = croppedCanvasEl.getContext('2d');

croppedCanvasEl.width = cropping.width || this.width;
croppedCanvasEl.height = cropping.height || this.height;

croppedCtx.drawImage(canvasEl, -cropping.left || 0, -cropping.top || 0);
}

return croppedCanvasEl;
},

/**
* @private
*/
__toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {

var origWidth = this.getWidth(),
origHeight = this.getHeight(),
scaledWidth = origWidth * multiplier,
scaledHeight = origHeight * multiplier,
activeObject = this._activeObject,
activeGroup = this._activeGroup,
zoom = this.getZoom(),
newZoom = zoom * multiplier / fabric.devicePixelRatio;

if (multiplier > 1) {
this.setDimensions({ width: scaledWidth, height: scaledHeight });
}

this.setZoom(newZoom);

if (cropping.left) {
cropping.left *= multiplier;
}
if (cropping.top) {
cropping.top *= multiplier;
}
if (cropping.width) {
cropping.width *= multiplier;
}
else if (multiplier < 1) {
cropping.width = scaledWidth;
}
if (cropping.height) {
cropping.height *= multiplier;
}
else if (multiplier < 1) {
cropping.height = scaledHeight;
}

if (activeGroup) {
// not removing group due to complications with restoring it with correct state afterwords
this._tempRemoveBordersControlsFromGroup(activeGroup);
}
else if (activeObject && this.deactivateAll) {
this.deactivateAll();
}

var data = this.__toDataURL(format, quality, cropping);
if (activeGroup) {
this._restoreBordersControlsOnGroup(activeGroup);
}
else if (activeObject && this.setActiveObject) {
this.setActiveObject(activeObject);
}
this.setZoom(zoom);
//setDimensions with no option object is taking care of:
//this.width, this.height, this.renderAll()
this.setDimensions({ width: origWidth, height: origHeight });

return data;
},

/**
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
* @deprecated since 1.0.13
* @param {String} format (png|jpeg)
* @param {Number} multiplier
* @param {Number} quality (0..1)
* @return {String}
*/
toDataURLWithMultiplier: function (format, multiplier, quality) {
return this.toDataURL({
format: format,
multiplier: multiplier,
quality: quality
});
},

/**
* @private
*/
_tempRemoveBordersControlsFromGroup: function(group) {
group.origHasControls = group.hasControls;
group.origBorderColor = group.borderColor;

group.hasControls = true;
group.borderColor = 'rgba(0,0,0,0)';

group.forEachObject(function(o) {
o.origBorderColor = o.borderColor;
o.borderColor = 'rgba(0,0,0,0)';
});
},

/**
* @private
*/
_restoreBordersControlsOnGroup: function(group) {
group.hideControls = group.origHideControls;
group.borderColor = group.origBorderColor;

group.forEachObject(function(o) {
o.borderColor = o.origBorderColor;
delete o.origBorderColor;
});
}
});
},

/**
* @private
*/
__toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {

var origWidth = this.getWidth(),
origHeight = this.getHeight(),
scaledWidth = (cropping.width || this.getWidth()) * multiplier,
scaledHeight = (cropping.width || this.getHeight()) * multiplier,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For scaledHeight, this should be cropping.height (not cropping.width).

zoom = this.getZoom(),
newZoom = zoom * multiplier,
vp = this.viewportTransform,
translateX = (vp[4] - cropping.left) * multiplier,
translateY = (vp[5] - cropping.top) * multiplier,
newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
originalInteractive = this.interactive;

this.viewportTransform = newVp;
// setting interactive to false avoid exporting controls
this.interactive && (this.interactive = false);
if (origWidth !== scaledWidth || origHeight !== scaledHeight) {
// this.setDimensions is going to renderAll also;
this.setDimensions({ width: scaledWidth, height: scaledHeight });
}
else {
this.renderAll();
}
var data = this.__toDataURL(format, quality, cropping);
originalInteractive && (this.interactive = originalInteractive);
this.viewportTransform = vp;
//setDimensions with no option object is taking care of:
//this.width, this.height, this.renderAll()
this.setDimensions({ width: origWidth, height: origHeight });
return data;
},

/**
* @private
*/
__toDataURL: function(format, quality) {

var canvasEl = this.contextContainer.canvas;
// to avoid common confusion https://github.com/kangax/fabric.js/issues/806
if (format === 'jpg') {
format = 'jpeg';
}

var data = supportQuality
? canvasEl.toDataURL('image/' + format, quality)
: canvasEl.toDataURL('image/' + format);

return data;
},

/**
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
* @deprecated since 1.0.13
* @param {String} format (png|jpeg)
* @param {Number} multiplier
* @param {Number} quality (0..1)
* @return {String}
*/
toDataURLWithMultiplier: function (format, multiplier, quality) {
return this.toDataURL({
format: format,
multiplier: multiplier,
quality: quality
});
},
});

})();
Loading