Thomas Bruederli
2012-11-10 03149131f754dd122f8707fbfc9e7ff47e9d6524
New feature: display attached images as thumbnails below message body
8 files modified
221 ■■■■■ changed files
config/main.inc.php.dist 5 ●●●●● patch | view | raw | blame | history
program/include/html.php 4 ●●●● patch | view | raw | blame | history
program/include/rcube_image.php 23 ●●●● patch | view | raw | blame | history
program/steps/mail/func.inc 49 ●●●● patch | view | raw | blame | history
program/steps/mail/get.inc 36 ●●●●● patch | view | raw | blame | history
skins/classic/mail.css 59 ●●●●● patch | view | raw | blame | history
skins/larry/mail.css 43 ●●●●● patch | view | raw | blame | history
skins/larry/templates/messagepart.html 2 ●●● patch | view | raw | blame | history
config/main.inc.php.dist
@@ -373,6 +373,11 @@
// 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;
program/include/html.php
@@ -252,9 +252,9 @@
     * @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);
    }
    /**
program/include/rcube_image.php
@@ -78,10 +78,11 @@
     *
     * @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 @@
            }
            $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 @@
            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;
            }
        }
program/steps/mail/func.inc
@@ -1186,7 +1186,9 @@
  }
  // 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 @@
      // 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,
              )))
          );
        }
      }
    }
  }
program/steps/mail/get.inc
@@ -60,6 +60,42 @@
  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]) {
skins/classic/mail.css
@@ -1254,6 +1254,65 @@
  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;
skins/larry/mail.css
@@ -1050,10 +1050,51 @@
    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;
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">