diff --git a/src/elements_parser.js b/src/elements_parser.js index 021332a5c74..6be9d189748 100644 --- a/src/elements_parser.js +++ b/src/elements_parser.js @@ -47,12 +47,13 @@ fabric.ElementsParser.prototype._createObject = function(klass, el, index) { fabric.ElementsParser.prototype.createCallback = function(index, el) { var _this = this; return function(obj) { + var _options; _this.resolveGradient(obj, 'fill'); _this.resolveGradient(obj, 'stroke'); - obj._removeTransformMatrix(); if (obj instanceof fabric.Image) { - obj.parsePreserveAspectRatioAttribute(el); + _options = obj.parsePreserveAspectRatioAttribute(el); } + obj._removeTransformMatrix(_options); _this.reviver && _this.reviver(el, obj); _this.instances[index] = obj; _this.checkIfDone(); diff --git a/src/shapes/image.class.js b/src/shapes/image.class.js index 8d325521e3e..aef447ae81e 100644 --- a/src/shapes/image.class.js +++ b/src/shapes/image.class.js @@ -549,53 +549,69 @@ : 0); }, + /** + * Calculate offset for center and scale factor for the image in order to respect + * the preserveAspectRatio attribute + * @private + * @return {Object} + */ parsePreserveAspectRatioAttribute: function() { - if (!this.preserveAspectRatio) { - return; - } - var pAR = fabric.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio), - width = this._element.width, height = this._element.height, scale, - pWidth = this.width, pHeight = this.height, parsedAttributes = { width: pWidth, height: pHeight }; + var pAR = fabric.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio || ''), + rWidth = this._element.width, rHeight = this._element.height, + scaleX = 1, scaleY = 1, offsetLeft = 0, offsetTop = 0, cropX = 0, cropY = 0, + offset, pWidth = this.width, pHeight = this.height, parsedAttributes = { width: pWidth, height: pHeight }; if (pAR && (pAR.alignX !== 'none' || pAR.alignY !== 'none')) { if (pAR.meetOrSlice === 'meet') { - this.width = width; - this.height = height; - this.scaleX = this.scaleY = scale = fabric.util.findScaleToFit(this._element, parsedAttributes); - if (pAR.alignX === 'Mid') { - this.left += (pWidth - width * scale) / 2; + scaleX = scaleY = fabric.util.findScaleToFit(this._element, parsedAttributes); + offset = (pWidth - rWidth * scaleX) / 2; + if (pAR.alignX === 'Min') { + offsetLeft = -offset; } if (pAR.alignX === 'Max') { - this.left += pWidth - width * scale; + offsetLeft = offset; } - if (pAR.alignY === 'Mid') { - this.top += (pHeight - height * scale) / 2; + offset = (pHeight - rHeight * scaleY) / 2; + if (pAR.alignY === 'Min') { + offsetTop = -offset; } if (pAR.alignY === 'Max') { - this.top += pHeight - height * scale; + offsetTop = offset; } } if (pAR.meetOrSlice === 'slice') { - this.scaleX = this.scaleY = scale = fabric.util.findScaleToCover(this._element, parsedAttributes); - this.width = pWidth / scale; - this.height = pHeight / scale; + scaleX = scaleY = fabric.util.findScaleToCover(this._element, parsedAttributes); + offset = rWidth - pWidth / scaleX; if (pAR.alignX === 'Mid') { - this.cropX = (width - this.width) / 2; + cropX = offset / 2; } if (pAR.alignX === 'Max') { - this.cropX = width - this.width; + cropX = offset; } + offset = rHeight - pHeight / scaleY; if (pAR.alignY === 'Mid') { - this.cropY = (height - this.height) / 2; + cropY = offset / 2; } if (pAR.alignY === 'Max') { - this.cropY = height - this.height; + cropY = offset; } + rWidth = pWidth / scaleX; + rHeight = pHeight / scaleY; } } else { - this.scaleX = pWidth / width; - this.scaleY = pHeight / height; + scaleX = pWidth / rWidth; + scaleY = pHeight / rHeight; } + return { + width: rWidth, + height: rHeight, + scaleX: scaleX, + scaleY: scaleY, + offsetLeft: offsetLeft, + offsetTop: offsetTop, + cropX: cropX, + cropY: cropY + }; } }); @@ -668,7 +684,6 @@ */ fabric.Image.fromElement = function(element, callback, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES); - fabric.Image.fromURL(parsedAttributes['xlink:href'], callback, extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes)); }; diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 24b1bdacc6a..fce2f25a792 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -1329,16 +1329,26 @@ * This function is an helper for svg import. it removes the transform matrix * and set to object properties that fabricjs can handle * @private - * @chainable + * @param {Object} preserveAspectRatioOptions * @return {thisArg} */ - _removeTransformMatrix: function() { + _removeTransformMatrix: function(preserveAspectRatioOptions) { var center = this._findCenterFromElement(); if (this.transformMatrix) { this._assignTransformMatrixProps(); center = fabric.util.transformPoint(center, this.transformMatrix); } this.transformMatrix = null; + if (preserveAspectRatioOptions) { + this.scaleX *= preserveAspectRatioOptions.scaleX; + this.scaleY *= preserveAspectRatioOptions.scaleY; + this.cropX = preserveAspectRatioOptions.cropX; + this.cropY = preserveAspectRatioOptions.cropY; + center.x += preserveAspectRatioOptions.offsetLeft; + center.y += preserveAspectRatioOptions.offsetTop; + this.width = preserveAspectRatioOptions.width; + this.height = preserveAspectRatioOptions.height; + } this.setPositionByOrigin(center, 'center', 'center'); }, diff --git a/test/unit/image.js b/test/unit/image.js index fbaca1c97e5..ebc945f0494 100644 --- a/test/unit/image.js +++ b/test/unit/image.js @@ -10,6 +10,23 @@ return src; } + function makeImageElement(attributes) { + var element = {}; + if (fabric.isLikelyNode) { + element.getAttribute = function(x) { + return element[x]; + }; + element.setAttribute = function(x, value) { + element[x] = value; + }; + } + for (var prop in attributes) { + element.setAttribute(prop, attributes[prop]); + } + return element; + } + + var IMG_SRC = fabric.isLikelyNode ? (__dirname + '/../fixtures/test_image.gif') : getAbsolutePath('../fixtures/test_image.gif'), IMG_WIDTH = 276, IMG_HEIGHT = 110; @@ -353,21 +370,6 @@ QUnit.test('fromElement', function(assert) { var done = assert.async(); - function makeImageElement(attributes) { - var element = _createImageElement(); - if (fabric.isLikelyNode) { - element.getAttribute = function(x) { - return element[x]; - }; - element.setAttribute = function(x, value) { - element[x] = value; - }; - } - for (var prop in attributes) { - element.setAttribute(prop, attributes[prop]); - } - return element; - } var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; @@ -388,24 +390,202 @@ }); }); - // QUnit.test('minimumScale', function(assert) { - // var done = assert.async(); - // createImageObject(function(image) { - // assert.ok(typeof image.toObject === 'function'); - // var filter = new fabric.Image.filters.Resize({resizeType: 'sliceHack', scaleX: 0.2, scaleY: 0.2}); - // image.resizeFilters.push(filter); - // var width = image.width, height = image.height; - // assert.ok(image.resizeFilters[0] instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); - // var toObject = image.toObject(); - // fabric.Image.fromObject(toObject, function(_imageFromObject) { - // var filterFromObj = _imageFromObject.resizeFilters[0]; - // assert.ok(filterFromObj instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); - // assert.equal(filterFromObj.scaleY, 0.2); - // assert.equal(filterFromObj.scaleX, 0.2); - // var canvasEl = _imageFromObject.applyFilters(null, _imageFromObject.resizeFilters, _imageFromObject._originalElement, true); - // done(); - // }); - // }); - // }); + QUnit.test('fromElement with preserveAspectRatio', function(assert) { + var done = assert.async(); + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + width: '140', + height: '170', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.ok(imgObject instanceof fabric.Image); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('scaleX'), 10, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 10, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller bbox', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '70', + height: '170', + preserveAspectRatio: 'meet xMidYMid', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 0, 'left'); + assert.deepEqual(imgObject.get('top'), 42.5, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller bbox xMidYmax', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '70', + height: '170', + preserveAspectRatio: 'meet xMidYMax', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 0, 'left'); + assert.deepEqual(imgObject.get('top'), 85, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller bbox xMidYmin', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '70', + height: '170', + preserveAspectRatio: 'meet xMidYMin', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 0, 'left'); + assert.deepEqual(imgObject.get('top'), 0, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller V bbox xMinYMin', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '140', + height: '85', + preserveAspectRatio: 'meet xMinYMin', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 0, 'left'); + assert.deepEqual(imgObject.get('top'), 0, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller V bbox xMidYmin', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '140', + height: '85', + preserveAspectRatio: 'meet xMidYMin', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 35, 'left'); + assert.deepEqual(imgObject.get('top'), 0, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); + + QUnit.test('fromElement with preserveAspectRatio and smaller V bbox xMaxYMin', function(assert) { + var done = assert.async(); + + var IMAGE_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAARCAYAAADtyJ2fAAAACXBIWXMAAAsSAAALEgHS3X78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVBJREFUeNqMU7tOBDEMtENuy614/QE/gZBOuvJK+Et6CiQ6JP6ExxWI7bhL1vgVExYKLPmsTTIzjieHd+MZZSBIAJwEyJU0EWaum+lNljRux3O6nl70Gx/GUwUeyYcDJWZNhMK1aEXYe95Mz4iP44kDTRUZSWSq1YEHri0/HZxXfGSFBN+qDEJTrNI+QXRBviZ7eWCQgjsg+IHiHYB30MhqUxwcmH1Arc2kFDwkBldeFGJLPqs/AbbF2dWgUym6Z2Tb6RVzYxG1wUnmaNcOonZiU0++l6C7FzoQY42g3+8jz+GZ+dWMr1rRH0OjAFhPO+VJFx/vWDqPmk8H97CGBUYUiqAGW0PVe1+aX8j2Ll0tgHtvLx6AK9Tu1ZTFTQ0ojChqGD4qkOzeAuzVfgzsaTym1ClS+IdwtQCFooQMBTumNun1H6Bfcc9/MUn4R3wJMAAZH6MmA4ht4gAAAABJRU5ErkJggg=='; + + assert.ok(typeof fabric.Image.fromElement === 'function', 'fromElement should exist'); + + var imageEl = makeImageElement({ + x: '0', + y: '0', + width: '140', + height: '85', + preserveAspectRatio: 'meet xMaxYMin', + 'xlink:href': IMAGE_DATA_URL + }); + + fabric.Image.fromElement(imageEl, function(imgObject) { + imgObject._removeTransformMatrix(imgObject.parsePreserveAspectRatioAttribute()); + assert.deepEqual(imgObject.get('width'), 14, 'width of an object'); + assert.deepEqual(imgObject.get('height'), 17, 'height of an object'); + assert.deepEqual(imgObject.get('left'), 70, 'left'); + assert.deepEqual(imgObject.get('top'), 0, 'top is moved to stay in center'); + assert.deepEqual(imgObject.get('scaleX'), 5, 'scaleX compensate the width'); + assert.deepEqual(imgObject.get('scaleY'), 5, 'scaleY compensate the height'); + assert.deepEqual(imgObject.getSrc(), IMAGE_DATA_URL, 'src of an object'); + done(); + }); + }); })();