J'ai récemment parcouru de nombreux effets de recadrage d'images de sites Web. La plupart des méthodes sont présentées dans l'image ci-dessous (en empruntant une image à Script Home). Sélectionnez la position appropriée en modifiant la taille de la zone de recadrage.
Mais cet article présente une autre méthode de recadrage. La zone de recadrage est déterminée par le développeur et la taille de l'image est déterminée par l'utilisateur. . Sélectionnez la position appropriée en zoomant et en faisant glisser l'image, et conservez toujours le rapport hauteur/largeur de l'image dans le processus, comme indiqué dans l'image ci-dessus à droite.
Cette méthode présente principalement les avantages suivants :
La largeur et la hauteur du cadre de recadrage doivent être cohérentes avec le rapport hauteur/largeur réel utilisé pour éviter la déformation de l'image problèmes.
Ne limite pas la taille d'affichage de l'image et garantit la proportion originale de l'image. La taille originale peut être obtenue par mise à l'échelle
absolument, de placer l'une à l'intérieur du cadre de recadrage et l'autre à l'extérieur du cadre de recadrage et de définir l'effet de transparence, le cadre de recadrage overflow est masqué, gardant les deux images absolument synchronisées à tout moment.
<p class="jimu-crop-image" data-dojo-attach-point="cropSection"> <p class="viewer-box" data-dojo-attach-point="viewerBox"> <p class="viewer-content" data-dojo-attach-point="viewerContent"> <img class="viewer-image hide-image" data-dojo-attach-point="viewerImage" src=""> </p> <img class="base-image hide-image" data-dojo-attach-point="baseImage" data-dojo-attach-event="mousedown:_onViewerMouseDown,mouseup:_onViewerMouseUp"> <p class="controller"> <p class="zoom-out" data-dojo-attach-event="click:_onZoomOutClick">-</p> <p class="slider" data-dojo-attach-point="sliderNode"> <p class="button" data-dojo-attach-point="sliderButton" data-dojo-attach-event="mousedown:_onSliderMouseDown,mouseup:_onSliderMouseUp"></p> <p class="horizontal"></p> </p> <p class="zoom-in" data-dojo-attach-event="click:_onZoomInClick">+</p> </p> </p> </p>
du document dans postCreate. sera toujours Vous pouvez continuer à faire glisser ou à zoomer. Le prochain travail principal concerne les fonctions startup et _init. Les amis qui ne sont pas familiers avec le dojo doivent seulement savoir que postCreate sera exécuté avant le démarrage.
startup: function() { var timeOut = /data:image\/(.*);base64/.test(this.imageSrc) ? 50 : 500; var tic = lang.hitch(this, function() { var imageStyle = html.getComputedStyle(this.baseImage); var imageWidth = parseFloat(imageStyle.width); console.log('image width', imageWidth); if (isFinite(imageWidth) && imageWidth > 0) { this._init(); } else { setTimeout(tic, timeOut); } }); setTimeout(tic, timeOut); }, _init: function() { debugger; var cropSectionStyle = html.getComputedStyle(this.cropSection); var cropSectionContentBox = html.getContentBox(this.cropSection); var imageStyle = html.getComputedStyle(this.baseImage); var imageWidth = parseFloat(imageStyle.width); var imageHeight = parseFloat(imageStyle.height); var imageRadio = imageWidth / imageHeight; this._maxImageWidth = imageWidth; this._maxImageHeight = imageHeight; if (imageHeight < this.realHeight && imageWidth < this.realWidth) { alert('image is too smaller to display'); return; } //create a box which keep the ratio of width and height to full fill the content of popup this.idealWidth = this.realWidth; this.idealHeight = this.realHeight; this.ratio = this.ratio ? this.ratio : this.realWidth / this.realHeight; if (this.ratio >= 1) { if (this.realWidth <= cropSectionContentBox.w) { this.idealWidth += (cropSectionContentBox.w - this.realWidth) / 2; } else { this.idealWidth = cropSectionContentBox.w; } this.idealHeight = this.idealWidth / this.ratio; } else { if (this.realHeight <= cropSectionContentBox.h) { this.idealHeight += (cropSectionContentBox.h - this.idealHeight) / 2; } else { this.idealHeight = cropSectionContentBox.h; } this.idealWidth = this.idealHeight * this.ratio; } html.setStyle(this.viewerBox, { width: this.idealWidth + 'px', height: this.idealHeight + 'px' }); var paddingTop = Math.abs((parseFloat(cropSectionStyle.height) - this.idealHeight) / 2); html.setStyle(this.cropSection, { 'paddingTop': paddingTop + 'px', 'paddingBottom': paddingTop + 'px' }); // keep original ratio of image if (imageRadio >= 1) { if (this.idealHeight * imageRadio >= this.idealWidth) { html.setStyle(this.viewerImage, 'height', this.idealHeight + 'px'); html.setStyle(this.baseImage, 'height', this.idealHeight + 'px'); } else { var properlyHeight = this._findProperlyValue(0, this.idealWidth, this.idealWidth, function(p) { return p * imageRadio; }); html.setStyle(this.viewerImage, 'height', properlyHeight + 'px'); html.setStyle(this.baseImage, 'height', properlyHeight + 'px'); } } else { if (this.idealWidth / imageRadio >= this.idealHeight) { html.setStyle(this.viewerImage, 'width', this.idealWidth + 'px'); html.setStyle(this.baseImage, 'width', this.idealWidth + 'px'); } else { var properlyWidth = this._findProperlyValue(0, this.idealHeight, this.idealHeight, function(p) { return p / imageRadio; }); html.setStyle(this.viewerImage, 'width', properlyWidth + 'px'); html.setStyle(this.baseImage, 'width', properlyWidth + 'px'); } } query('.hide-image', this.domNode).removeClass('hide-image'); imageStyle = html.getComputedStyle(this.baseImage); imageWidth = parseFloat(imageStyle.width); imageHeight = parseFloat(imageStyle.height); this._minImageWidth = imageWidth; this._minImageHeight = imageHeight; this._currentImageWidth = imageWidth; this._currentImageHeight = imageHeight; this._currentTop = -(imageHeight - this.idealHeight) / 2; this._currentLeft = -(imageWidth - this.idealWidth) / 2; html.setStyle(this.baseImage, { top: this._currentTop + 'px', left: this._currentLeft + 'px' }); html.setStyle(this.viewerImage, { top: this._currentTop + 'px', left: this._currentLeft + 'px' }); //sometimes zoomratio < 1; it's should be not allowed to zoom this._zoomRatio = this._maxImageWidth / this._minImageWidth; if (!this._latestPercentage) { this._latestPercentage = 0; } },
_resetImagePosition: function(clientX, clientY) { var delX = clientX - this._currentX; var delY = clientY - this._currentY; if (this._currentTop + delY >= 0) { html.setStyle(this.baseImage, 'top', 0); html.setStyle(this.viewerImage, 'top', 0); this._currentY = clientY; this._currentTop = 0; } else if (this._currentTop + delY <= this._maxOffsetTop) { html.setStyle(this.baseImage, 'top', this._maxOffsetTop + 'px'); html.setStyle(this.viewerImage, 'top', this._maxOffsetTop + 'px'); this._currentY = clientY; this._currentTop = this._maxOffsetTop; } else { html.setStyle(this.baseImage, 'top', this._currentTop + delY + 'px'); html.setStyle(this.viewerImage, 'top', this._currentTop + delY + 'px'); this._currentY = clientY; this._currentTop += delY; } if (this._currentLeft + delX >= 0) { html.setStyle(this.baseImage, 'left', 0); html.setStyle(this.viewerImage, 'left', 0); this._currentX = clientX; this._currentLeft = 0; } else if (this._currentLeft + delX <= this._maxOffsetLeft) { html.setStyle(this.baseImage, 'left', this._maxOffsetLeft + 'px'); html.setStyle(this.viewerImage, 'left', this._maxOffsetLeft + 'px'); this._currentX = clientX; this._currentLeft = this._maxOffsetLeft; } else { html.setStyle(this.baseImage, 'left', this._currentLeft + delX + 'px'); html.setStyle(this.viewerImage, 'left', this._currentLeft + delX + 'px'); this._currentX = clientX; this._currentLeft += delX; } },
garder la position relative du point central du cadre de recadrage inchangée avant et après la mise à l'échelle.
Afin de déplacer le point central de la zone de recadrage d'origine mise à l'échelle vers sa position d'origine, nous devons calculer la médiane de deux valeurs : taille de l'image Montant du changement, la quantité de mouvement du coin supérieur gauche de l'image.var delImageWidth = this._minImageWidth * (this._zoomRatio - 1) * leftPercentage / 100; var delImageHeight = this._minImageHeight * (this._zoomRatio - 1) * leftPercentage / 100; var imageStyle = html.getComputedStyle(this.baseImage); this._currentLeft = parseFloat(imageStyle.left); this._currentTop = parseFloat(imageStyle.top); var delImageLeft = (Math.abs(this._currentLeft) + this.idealWidth / 2) * ((this._minImageWidth + delImageWidth) / this._currentImageWidth - 1); var delImageTop = (Math.abs(this._currentTop) + this.idealHeight / 2) * ((this._minImageWidth + delImageWidth) / this._currentImageWidth - 1);
//prevent image out the crop box if (leftPercentage - _latestPercentage >= 0) { console.log('zoomin'); html.setStyle(this.baseImage, { top: this._currentTop -delImageTop + 'px', left: this._currentLeft -delImageLeft + 'px' }); html.setStyle(this.viewerImage, { top: this._currentTop -delImageTop + 'px', left: this._currentLeft -delImageLeft + 'px' }); } else { console.log('zoomout'); var top = 0; var left = 0; if (this._currentTop - delImageTop >= 0) { top = 0; } else if (this._currentTop - delImageTop + this._minImageHeight + delImageHeight <= this.idealHeight) { top = this.idealHeight - this._minImageHeight - delImageHeight; } else { top = this._currentTop - delImageTop; } console.log(this._currentLeft, delImageLeft); if (this._currentLeft - delImageLeft >= 0) { left = 0; } else if (this._currentLeft - delImageLeft + this._minImageWidth + delImageWidth <= this.idealWidth) { left =this.idealWidth - this._minImageWidth - delImageWidth; } else { left = this._currentLeft - delImageLeft; } html.setStyle(this.baseImage, { top: top + 'px', left: left + 'px' }); html.setStyle(this.viewerImage, { top: top + 'px', left: left + 'px' }); }
服务器端使用nodejs+express框架,主要代码如下:
/********** body: { imageString: base64 code maxSize: w,h cropOptions: w,h,t,l } ************/ exports.cropImage = function(req, res) { var base64Img = req.body.imageString; if(!/^data:image\/.*;base64,/.test(base64Img)){ res.send({ success: false, message: 'Bad base64 code format' }); } var fileFormat = base64Img.match(/^data:image\/(.*);base64,/)[1]; var base64Data = base64Img.replace(/^data:image\/.*;base64,/, ""); var maxSize = req.body.maxSize; maxSize = maxSize.split(','); var cropOptions = req.body.cropOptions; cropOptions = cropOptions.split(','); try{ var buf = new Buffer(base64Data, 'base64'); var jimp = new Jimp(buf, 'image/' + fileFormat, function() { var maxW = parseInt(maxSize[0], 10); var maxH = parseInt(maxSize[1], 10); var cropW = parseInt(cropOptions[0], 10); var cropH = parseInt(cropOptions[1], 10); var cropT = parseInt(cropOptions[2], 10); var cropL = parseInt(cropOptions[3], 10); this.resize(maxW, maxH) .crop(cropT, cropL, cropW, cropH); }); jimp.getBuffer('image/' + fileFormat, function(b) { var base64String = "data:image/" + fileFormat + ";base64," + b.toString('base64'); res.send({ success: true, source: base64String }); }); }catch(err) { logger.error(err); res.send({ success: false, message: 'unable to complete operations' }); } };
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!