diff --git a/application/Espo/EntryPoints/Image.php b/application/Espo/EntryPoints/Image.php index b76a823f5d..64dbcc541e 100644 --- a/application/Espo/EntryPoints/Image.php +++ b/application/Espo/EntryPoints/Image.php @@ -42,7 +42,8 @@ class Image extends \Espo\Core\EntryPoints\Base 'small' => array(128, 128), 'medium' => array(256, 256), 'large' => array(512, 512), - 'xlarge' => array(1024, 1024), + 'xlarge' => array(864, 864), + 'xxlarge' => array(1024, 1024), ); public function run() @@ -67,11 +68,11 @@ class Image extends \Espo\Core\EntryPoints\Base } } - $fileName = "data/upload/{$attachment->id}"; + $filePath = "data/upload/{$attachment->id}"; $fileType = $attachment->get('type'); - if (!file_exists($fileName)) { + if (!file_exists($filePath)) { throw new NotFound(); } @@ -80,58 +81,76 @@ class Image extends \Espo\Core\EntryPoints\Base } if (!empty($size)) { - if (!empty($this->imageSizes[$size])) { - // TODO cache thumbs - list($originalWidth, $originalHeight) = getimagesize($fileName); - list($width, $height) = $this->imageSizes[$size]; + if (!empty($this->imageSizes[$size])) { + $thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}"; - if ($originalWidth > $width && ($originalHeight <= $height || $originalWidth > $originalHeight)) { - $targetWidth = $width; - $targetHeight = $originalHeight * ($width / $originalWidth); - } else if ($originalHeight > $height && ($originalWidth <= $width || $originalHeight > $originalWidth)) { - $targetHeight = $height; - $targetWidth = $originalWidth * ($height / $targetHeight); - } else { - $targetWidth = $originalWidth; - $targetHeight = $originalHeight; - } - - $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); - switch ($fileType) { - case 'image/jpeg': - $sourceImage = imagecreatefromjpeg($fileName); - break; - case 'image/png': - $sourceImage = imagecreatefrompng($fileName); - break; - case 'image/gif': - $sourceImage = imagecreatefromgif($fileName); - break; - } - imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + if (!file_exists($thumbFilePath)) { + $targetImage = $this->getThumbImage($filePath, $fileType, $size); + ob_start(); + imagejpeg($targetImage); + $contents = ob_get_contents(); + ob_end_clean(); + imagedestroy($targetImage); + $this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents); + } + $filePath = $thumbFilePath; + } else { throw new Error(); } } - + if (!empty($size)) { + $fileName = $attachment->id . '_' . $size . '.jpg'; + } else { + $fileName = $attachment->get('name'); + } + header('Content-Disposition:inline;filename="'.$fileName.'"'); if (!empty($fileType)) { header('Content-Type: ' . $fileType); } header('Pragma: public'); - - if (!empty($targetImage)) { - ob_clean(); - flush(); - imagejpeg($targetImage); - imagedestroy($targetImage); - } else { - header('Content-Length: ' . filesize($fileName)); - ob_clean(); - flush(); - readfile($fileName); + $fileSize = filesize($filePath); + if ($fileSize) { + header('Content-Length: ' . $fileSize); } + ob_clean(); + flush(); + readfile($filePath); exit; - } + } + + protected function getThumbImage($filePath, $fileType, $size) + { + list($originalWidth, $originalHeight) = getimagesize($filePath); + list($width, $height) = $this->imageSizes[$size]; + + if ($originalWidth > $width && ($originalHeight <= $height || $originalWidth > $originalHeight)) { + $targetWidth = $width; + $targetHeight = $originalHeight * ($width / $originalWidth); + } else if ($originalHeight > $height && ($originalWidth <= $width || $originalHeight > $originalWidth)) { + $targetHeight = $height; + $targetWidth = $originalWidth * ($height / $targetHeight); + } else { + $targetWidth = $originalWidth; + $targetHeight = $originalHeight; + } + + $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); + switch ($fileType) { + case 'image/jpeg': + $sourceImage = imagecreatefromjpeg($filePath); + break; + case 'image/png': + $sourceImage = imagecreatefrompng($filePath); + break; + case 'image/gif': + $sourceImage = imagecreatefromgif($filePath); + break; + } + imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + + return $targetImage; + } } diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 66d51f6488..205d86a88a 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -103,6 +103,7 @@ "Person": "Person", "First Name": "First Name", "Last Name": "Last Name", + "Original": "Original", "You": "You", "you": "you" }, diff --git a/frontend/client/res/templates/modals/image-preview.tpl b/frontend/client/res/templates/modals/image-preview.tpl new file mode 100644 index 0000000000..b97e949165 --- /dev/null +++ b/frontend/client/res/templates/modals/image-preview.tpl @@ -0,0 +1,7 @@ +
+ +
+ +
+{{translate 'Original'}}: {{name}} +
diff --git a/frontend/client/src/views/fields/attachment-multiple.js b/frontend/client/src/views/fields/attachment-multiple.js index 8a36e0da49..ebf7e1a169 100644 --- a/frontend/client/src/views/fields/attachment-multiple.js +++ b/frontend/client/src/views/fields/attachment-multiple.js @@ -63,6 +63,17 @@ Espo.define('Views.Fields.AttachmentMultiple', 'Views.Fields.Base', function (De $file.replaceWith($file.clone(true)); }, + 'click a[data-action="showImagePreview"]': function (e) { + + var id = $(e.currentTarget).data('id'); + this.createView('preview', 'Modals.ImagePreview', { + id: id, + model: this.model, + name: this.nameHash[id] + }, function (view) { + view.render(); + }); + }, }, data: function () { @@ -164,7 +175,6 @@ Espo.define('Views.Fields.AttachmentMultiple', 'Views.Fields.Base', function (De }, addAttachmentBox: function (name, type, id) { - console.log(name, type, id); $attachments = this.$attachments; var self = this; @@ -256,7 +266,7 @@ Espo.define('Views.Fields.AttachmentMultiple', 'Views.Fields.Base', function (De }, - afterRender: function () { + afterRender: function () { if (this.mode == 'edit') { this.$attachments = this.$el.find('div.attachments'); @@ -283,7 +293,7 @@ Espo.define('Views.Fields.AttachmentMultiple', 'Views.Fields.Base', function (De case 'image/png': case 'image/jpeg': case 'image/gif': - preview = ''; + preview = ''; } return preview; }, diff --git a/frontend/client/src/views/modals/image-preview.js b/frontend/client/src/views/modals/image-preview.js new file mode 100644 index 0000000000..dd3a268796 --- /dev/null +++ b/frontend/client/src/views/modals/image-preview.js @@ -0,0 +1,72 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Modals.ImagePreview', 'Views.Modal', function (Dep) { + + return Dep.extend({ + + cssName: 'image-preview', + + header: true, + + template: 'modals.image-preview', + + size: 'xlarge', + + data: function () { + return { + id: this.options.id, + name: this.options.name, + size: this.size + }; + }, + + setup: function () { + this.buttons = []; + this.header = ' '; + }, + + afterRender: function () { + $container = this.$el.find('.image-container'); + $img = this.$el.find('.image-container img'); + + var manageSize = function () { + var width = this.$el.width(); + if (width < 868) { + $img.attr('width', width); + } else { + $img.removeAttr('width'); + } + }.bind(this); + + $(window).on('resize', function () { + manageSize(); + }); + + setTimeout(function () { + manageSize(); + }, 100); + + }, + + }); +}); + diff --git a/frontend/client/src/views/stream/note.js b/frontend/client/src/views/stream/note.js index ad05bc19d0..56ce90a27c 100644 --- a/frontend/client/src/views/stream/note.js +++ b/frontend/client/src/views/stream/note.js @@ -66,6 +66,7 @@ Espo.define('Views.Stream.Note', 'View', function (Dep) { name: name, params: params || {} }, + el: this.options.el + ' .cell-' + name, mode: 'list' });