summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <thomas@roundcube.net>2012-11-10 21:08:14 +0100
committerThomas Bruederli <thomas@roundcube.net>2012-11-10 21:08:14 +0100
commit03149131f754dd122f8707fbfc9e7ff47e9d6524 (patch)
tree0bd2d3ea9d6582a5b7b460b9c620234e294b52d9
parent25a86bacf6b5ed30b78d33ad656c48458876e102 (diff)
New feature: display attached images as thumbnails below message body
-rw-r--r--config/main.inc.php.dist5
-rw-r--r--program/include/html.php4
-rw-r--r--program/include/rcube_image.php23
-rw-r--r--program/steps/mail/func.inc49
-rw-r--r--program/steps/mail/get.inc36
-rw-r--r--skins/classic/mail.css59
-rw-r--r--skins/larry/mail.css43
-rw-r--r--skins/larry/templates/messagepart.html2
8 files changed, 204 insertions, 17 deletions
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 35fe0e8f6..dc76f1887 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -373,6 +373,11 @@ $rcmail_config['im_identify_path'] = null;
// path to imagemagick convert binary
$rcmail_config['im_convert_path'] = null;
+// Size of thumbnails from image attachments displayed below the message content.
+// Note: whether images are displayed at all depends on the 'inline_images' option.
+// Set to 0 to display images in full size.
+$rcmail_config['image_thumbnail_size'] = 240;
+
// maximum size of uploaded contact photos in pixel
$rcmail_config['contact_photo_size'] = 160;
diff --git a/program/include/html.php b/program/include/html.php
index 880873ddc..0f93e969d 100644
--- a/program/include/html.php
+++ b/program/include/html.php
@@ -252,9 +252,9 @@ class html
* @return string HTML code
* @see html::tag()
*/
- public static function br()
+ public static function br($attrib = array())
{
- return self::tag('br');
+ return self::tag('br', $attrib);
}
/**
diff --git a/program/include/rcube_image.php b/program/include/rcube_image.php
index 80e8bd4f3..c0d4e878d 100644
--- a/program/include/rcube_image.php
+++ b/program/include/rcube_image.php
@@ -78,10 +78,11 @@ class rcube_image
*
* @param int $size Max width/height size
* @param string $filename Output filename
+ * @param boolean $browser_compat Convert to image type displayable by any browser
*
- * @return bool True on success, False on failure
+ * @return mixed Output type on success, False on failure
*/
- public function resize($size, $filename = null)
+ public function resize($size, $filename = null, $browser_compat = false)
{
$result = false;
$rcube = rcube::get_instance();
@@ -104,15 +105,22 @@ class rcube_image
}
$type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
+ $p['intype'] = $type;
+
+ // convert to an image format every browser can display
+ if ($browser_compat && !in_array($type, array('jpg','gif','png'))) {
+ $type = 'jpg';
+ }
+
$p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
- $p['-opts'] = array('-resize' => $size.'>');
+ $p['-opts'] = array('-resize' => $p['size'].'>');
if (in_array($type, explode(',', $p['types']))) { // Valid type?
- $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p);
+ $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {intype}:{in} {type}:{out}', $p);
}
if ($result === '') {
- return true;
+ return $type;
}
}
@@ -148,16 +156,19 @@ class rcube_image
if ($props['gd_type'] == IMAGETYPE_JPEG) {
$result = imagejpeg($image, $filename, 75);
+ $type = 'jpg';
}
elseif($props['gd_type'] == IMAGETYPE_GIF) {
$result = imagegif($image, $filename);
+ $type = 'gid';
}
elseif($props['gd_type'] == IMAGETYPE_PNG) {
$result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
+ $type = 'png';
}
if ($result) {
- return true;
+ return $type;
}
}
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index f128a3834..c0d36daf4 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1186,7 +1186,9 @@ function rcmail_message_body($attrib)
}
// list images after mail body
- if ($CONFIG['inline_images'] && !empty($MESSAGE->attachments)) {
+ if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) {
+ $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
+
foreach ($MESSAGE->attachments as $attach_prop) {
// skip inline images
if ($attach_prop->content_id && $attach_prop->disposition == 'inline') {
@@ -1195,12 +1197,45 @@ function rcmail_message_body($attrib)
// Content-Type: image/*...
if (rcmail_part_image_type($attach_prop)) {
- $out .= html::tag('hr') . html::p(array('align' => "center"),
- html::img(array(
- 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true),
- 'title' => $attach_prop->filename,
- 'alt' => $attach_prop->filename,
- )));
+ // display thumbnails
+ if ($thumbnail_size) {
+ $show_link = array(
+ 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
+ 'onclick' => sprintf(
+ 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)',
+ JS_OBJECT_NAME,
+ $attach_prop->mime_id,
+ rcmail_fix_mimetype($attach_prop->mimetype))
+ );
+ $out .= html::p('image-attachment',
+ html::a($show_link + array('class' => 'image-link'),
+ html::img(array(
+ 'class' => 'image-thumbnail',
+ 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true) . '&_thumb=1',
+ 'title' => $attach_prop->filename,
+ 'alt' => $attach_prop->filename,
+ 'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
+ ))
+ ) .
+ html::span('image-filename', Q($attach_prop->filename)) .
+ html::span('image-filesize', Q($RCMAIL->show_bytes($attach_prop->size))) .
+ html::span('attachment-links',
+ html::a($show_link['href'] . '&_download=1', rcube_label('download'))
+ ) .
+ html::br(array('style' => 'clear:both'))
+ );
+ }
+ else {
+ $out .= html::tag('fieldset', 'image-attachment',
+ html::tag('legend', 'image-filename', Q($attach_prop->filename)) .
+ html::p(array('align' => "center"),
+ html::img(array(
+ 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true),
+ 'title' => $attach_prop->filename,
+ 'alt' => $attach_prop->filename,
+ )))
+ );
+ }
}
}
}
diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc
index bcd57dee0..2397358a1 100644
--- a/program/steps/mail/get.inc
+++ b/program/steps/mail/get.inc
@@ -60,6 +60,42 @@ if (!empty($_GET['_frame'])) {
exit;
}
+// render thumbnail of an image attachment
+else if ($_GET['_thumb']) {
+ $pid = get_input_value('_part', RCUBE_INPUT_GET);
+ if ($part = $MESSAGE->mime_parts[$pid]) {
+ $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
+ $temp_dir = $RCMAIL->config->get('temp_dir');
+ list(,$ext) = explode('/', $part->mimetype);
+ $cache_basename = $temp_dir . '/' . md5($MESSAGE->headers->messageID . $part->mime_id . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size);
+ $cache_file = $cache_basename . '.' . $ext;
+ $mimetype = $part->mimetype;
+
+ // render thumbnail image if not done yet
+ if (!is_file($cache_file)) {
+ $fp = fopen(($orig_name = $cache_basename . '.orig.' . $ext), 'w');
+ $MESSAGE->get_part_content($part->mime_id, $fp);
+ fclose($fp);
+
+ $image = new rcube_image($orig_name);
+ if ($imgtype = $image->resize($RCMAIL->config->get('image_thumbnail_size', 240), $cache_file, true)) {
+ $mimetype = 'image/' . $imgtype;
+ unlink($orig_name);
+ }
+ else {
+ rename($orig_name, $cache_file);
+ }
+ }
+
+ if (is_file($cache_file)) {
+ header('Content-Type: ' . $mimetype);
+ readfile($cache_file);
+ }
+ }
+
+ exit;
+}
+
else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) {
if ($part = $MESSAGE->mime_parts[$pid]) {
diff --git a/skins/classic/mail.css b/skins/classic/mail.css
index 7408d49f1..85c53d569 100644
--- a/skins/classic/mail.css
+++ b/skins/classic/mail.css
@@ -1254,6 +1254,65 @@ div.message-htmlpart div.rcmBody
color: #333333;
}
+#messagebody fieldset.image-attachment {
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 1em 0 1em;
+}
+
+#messagebody fieldset.image-attachment p > img
+{
+ max-width: 80%;
+}
+
+#messagebody legend.image-filename
+{
+ color: #999;
+ font-size: 0.9em;
+}
+
+#messagebody p.image-attachment
+{
+ margin: 0 1em;
+ padding: 1em;
+ border-top: 1px solid #ccc;
+}
+
+#messagebody p.image-attachment a.image-link
+{
+ float: left;
+ margin-right: 2em;
+ min-width: 160px;
+ min-height: 60px;
+ text-align: center;
+}
+
+#messagebody p.image-attachment .image-filename
+{
+ display: block;
+ font-weight: bold;
+ line-height: 1.6em;
+}
+
+#messagebody p.image-attachment .image-filesize
+{
+ font-size: 11px;
+ padding-right: 1em;
+}
+
+#messagebody p.image-attachment .attachment-links a
+{
+ margin-right: 0.6em;
+ color: #cc0000;
+ font-size: 11px;
+ text-decoration: none;
+}
+
+#messagebody p.image-attachment .attachment-links a:hover
+{
+ text-decoration: underline;
+}
+
#openextwinlink
{
position: absolute;
diff --git a/skins/larry/mail.css b/skins/larry/mail.css
index eb623222a..48560abe2 100644
--- a/skins/larry/mail.css
+++ b/skins/larry/mail.css
@@ -1050,10 +1050,51 @@ div.message-part blockquote blockquote blockquote {
border-bottom: 2px solid #f0f0f0;
}
-#messagebody > p > img {
+#messagebody fieldset.image-attachment {
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin-top: 1em;
+}
+
+#messagebody fieldset.image-attachment p > img {
max-width: 80%;
}
+#messagebody legend.image-filename {
+ color: #999;
+ font-size: 0.9em;
+ margin: 0 1em;
+}
+
+#messagebody p.image-attachment {
+ position: relative;
+ padding: 1em;
+ border-top: 1px solid #ccc;
+}
+
+#messagebody p.image-attachment a.image-link {
+ float: left;
+ display: block;
+ margin-right: 2em;
+ min-width: 160px;
+ min-height: 60px;
+ text-align: center;
+}
+
+#messagebody p.image-attachment .image-filename {
+ display: block;
+ font-weight: bold;
+ line-height: 1.6em;
+}
+
+#messagebody p.image-attachment .image-filesize {
+ padding-right: 1em;
+}
+
+#messagebody p.image-attachment .attachment-links a {
+ margin-right: 0.6em;
+}
+
#messagepartcontainer {
position: absolute;
top: 60px;
diff --git a/skins/larry/templates/messagepart.html b/skins/larry/templates/messagepart.html
index db078296f..e029973a8 100644
--- a/skins/larry/templates/messagepart.html
+++ b/skins/larry/templates/messagepart.html
@@ -4,7 +4,7 @@
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
-<body class="extwin">
+<body class="partwin">
<div id="header">
<div id="topline">