-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
+173
−258
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
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 | ||
}); | ||
}, | ||
}); | ||
|
||
})(); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For
scaledHeight
, this should becropping.height
(notcropping.width
).