diff --git a/inc/JpegMeta.php b/inc/JpegMeta.php index b9f0908d43f66741ae23609d9a86fe905058b259..408f34589d6af2dd5d96823f11ebeb58c044a130 100644 --- a/inc/JpegMeta.php +++ b/inc/JpegMeta.php @@ -3,9 +3,10 @@ * JPEG metadata reader/writer * * @license PHP license 2.0 (http://www.php.net/license/2_02.txt) - * @link + * @link http://www.zonageek.com/software/php/jpeg/index.php * @author Sebastian Delmont <sdelmont@zonageek.com> * @author Andreas Gohr <andi@splitbrain.org> + * @todo Add support for Maker Notes, Extend for GIF and PNG metadata */ // This class is a modified and enhanced version of the JPEG class by @@ -163,6 +164,40 @@ class JpegMeta return trim($info); } + /** + * Convinience function to set nearly all available Data + * through one function + * + * @author Andreas Gohr <andi@splitbrain.org> + */ + function setField($field, $value) + { + if(strtolower(substr($field,0,5)) == 'iptc.'){ + return $this->setIPTCField(substr($field,5),$value); + }elseif(strtolower(substr($field,0,5)) == 'exif.'){ + return $this->setExifField(substr($field,5),$value); + }else{ + return $this->setExifField($field,$value); + } + } + + /** + * Convinience function to delete nearly all available Data + * through one function + * + * @author Andreas Gohr <andi@splitbrain.org> + */ + function deleteField($field) + { + if(strtolower(substr($field,0,5)) == 'iptc.'){ + return $this->deleteIPTCField(substr($field,5)); + }elseif(strtolower(substr($field,0,5)) == 'exif.'){ + return $this->deleteExifField(substr($field,5)); + }else{ + return $this->deleteExifField($field); + } + } + /** * Return a date field * @@ -770,18 +805,19 @@ class JpegMeta * Save changed Metadata * * @author Sebastian Delmont <sdelmont@zonageek.com> + * @author Andreas Gohr <andi@splitbrain.org> */ function save($fileName = "") { - if ($fileName == "") { - $tmpName = $this->_fileName . ".tmp"; - $this->_writeJPEG($tmpName); - if (file_exists($tmpName)) { - rename($tmpName, $this->_fileName); - } - } - else { - $this->_writeJPEG($fileName); - } + if ($fileName == "") { + $tmpName = tempnam(dirname($this->_fileName),'_metatemp_'); + $this->_writeJPEG($tmpName); + if (@file_exists($tmpName)) { + return rename($tmpName, $this->_fileName); + } + } else { + return $this->_writeJPEG($fileName); + } + return false; } /*************************************************************/ diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index 16fc1b73897faa7fccfc694ad260757ab090e623..fcc4ed696eb214e5d7cf2540974800389ea29104 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -144,6 +144,9 @@ $lang['spell_noerr'] = 'No Mistakes found'; $lang['spell_nosug'] = 'No Suggestions'; $lang['spell_change']= 'Change'; +$lang['metaedit'] = 'Edit Metadata'; +$lang['metasaveerr'] = 'Writing metadata failed'; +$lang['metasaveok'] = 'Metadata saved'; $lang['img_backto'] = 'Back to'; $lang['img_title'] = 'Title'; $lang['img_caption'] = 'Caption'; diff --git a/inc/template.php b/inc/template.php index 23123b4522362cfb1557febd92501e85e9c822b2..b48a591f8926062125112c111e6b5b8f1d2d291a 100644 --- a/inc/template.php +++ b/inc/template.php @@ -665,12 +665,21 @@ function tpl_mediafilelist(){ $t = $item['meta']->getField('IPTC.Headline'); if($t) print '<b>'.$t.'</b><br />'; - $t = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment','EXIF.TIFFImageDescription','EXIF.TIFFUserComment')); + $t = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment', + 'EXIF.TIFFImageDescription', + 'EXIF.TIFFUserComment')); if($t) print $t.'<br />'; $t = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category')); if($t) print '<i>'.$t.'</i><br />'; + //add edit button + if($AUTH >= AUTH_UPLOAD && $item['meta']->getField('File.Mime') == 'image/jpeg'){ + print '<a href="'.DOKU_BASE.'lib/exe/media.php?edit='.urlencode($item['id']).'">'; + print '<img src="'.DOKU_BASE.'lib/images/edit.gif" alt="'.$lang['metaedit'].'" title="'.$lang['metaedit'].'" />'; + print '</a>'; + } + ptln('</div>',6); }else{ ptln ('('.filesize_h($item['size']).')',6); @@ -771,7 +780,7 @@ function tpl_pagetitle($id=null){ * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC * to the names of the latter one) * - * Only allowed in: detail.php + * Only allowed in: detail.php, mediaedit.php * * @author Andreas Gohr <andi@splitbrain.org> */ diff --git a/lib/exe/media.php b/lib/exe/media.php index c8db371534d2486d3422be3cdef7bc0186a01d3d..cddf258db29d3ae6edc96bfc87525f91d6cd9d5b 100644 --- a/lib/exe/media.php +++ b/lib/exe/media.php @@ -14,8 +14,12 @@ //get namespace to display (either direct or from deletion order) if($_REQUEST['delete']){ - $DEL = cleanID($_REQUEST['delete']); + $DEL = cleanID($_REQUEST['delete']); $NS = getNS($DEL); + }elseif($_REQUEST['edit']){ + $IMG = cleanID($_REQUEST['edit']); + $SRC = mediaFN($IMG); + $NS = getNS($IMG); }else{ $NS = $_REQUEST['ns']; $NS = cleanID($NS); @@ -35,9 +39,9 @@ //handle deletion $mediareferences = array(); if($DEL && $AUTH >= AUTH_DELETE){ - if($conf['refcheck']){ - search($mediareferences,$conf['datadir'],'search_reference',array('query' => $DEL)); - } + if($conf['refcheck']){ + search($mediareferences,$conf['datadir'],'search_reference',array('query' => $DEL)); + } if(!count($mediareferences)){ media_delete($DEL); }elseif(!$conf['refshow']){ @@ -45,6 +49,11 @@ } } + //handle metadatasaving + if($UPLOADOK && $SRC && $_REQUEST['save']){ + media_metasave($SRC,$_REQUEST['meta']); + } + //handle upload if($_FILES['upload']['tmp_name'] && $UPLOADOK){ media_upload($NS,$AUTH); @@ -54,6 +63,8 @@ header('Content-Type: text/html; charset=utf-8'); if($conf['refshow'] && count($mediareferences)){ include(template('mediaref.php')); + }elseif($IMG){ + include(template('mediaedit.php')); }else{ include(template('media.php')); } @@ -87,7 +98,7 @@ function media_delete($delid){ * @author Andreas Gohr <andi@splitbrain.org> */ function media_upload($NS,$AUTH){ - require_once(DOKU_INC.'inc/confutils.php'); + require_once(DOKU_INC.'inc/confutils.php'); global $lang; global $conf; @@ -101,24 +112,24 @@ function media_upload($NS,$AUTH){ $fn = mediaFN($id); // get filetype regexp - $types = array_keys(getMimeTypes()); - $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); + $types = array_keys(getMimeTypes()); + $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); $regex = join('|',$types); // we set the umask here but this doesn't really help // because a temp file was created already umask($conf['umask']); if(preg_match('/\.('.$regex.')$/i',$fn)){ - //check for overwrite - if(@file_exists($fn) && (!$_POST['ow'] || $AUTH < AUTH_DELETE)){ - msg($lang['uploadexist'],0); - return false; - } - // prepare directory - io_makeFileDir($fn); + //check for overwrite + if(@file_exists($fn) && (!$_POST['ow'] || $AUTH < AUTH_DELETE)){ + msg($lang['uploadexist'],0); + return false; + } + // prepare directory + io_makeFileDir($fn); if(move_uploaded_file($file['tmp_name'], $fn)) { - // set the correct permission here - chmod($fn, 0777 - $conf['umask']); + // set the correct permission here + chmod($fn, 0777 - $conf['umask']); msg($lang['uploadsucc'],1); return true; }else{ @@ -146,4 +157,31 @@ function media_html_list_namespaces($item){ return $ret; } +/** + * Saves image meta data + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function media_metasave($src,$data){ + global $lang; + + $meta = new JpegMeta($src); + $meta->_parseAll(); + + foreach($data as $key => $val){ + $val=trim($val); + if(empty($val)){ + $meta->deleteField($key); + }else{ + $meta->setField($key,$val); + } + } + + if($meta->save()){ + msg($lang['metasaveok'],1); + }else{ + msg($lang['metasaveerr'],-1); + } +} + ?> diff --git a/lib/images/edit.gif b/lib/images/edit.gif new file mode 100644 index 0000000000000000000000000000000000000000..a2a23de7b31c4f48a051d25272f9b24f8d7ac281 Binary files /dev/null and b/lib/images/edit.gif differ diff --git a/lib/tpl/default/design.css b/lib/tpl/default/design.css index 48453a736229b36ff37644f1c959e3606bedc620..ee03815ff731dad23404d8146b5635401f8b95fc 100644 --- a/lib/tpl/default/design.css +++ b/lib/tpl/default/design.css @@ -733,3 +733,25 @@ div.mediaselect-right li, div.uploadform { clear: both; } +div.mediaedit div.data label{ + display: block; + text-align: right; + width: 20%; + float: left; + margin-right: 0.5em; +} + +div.mediaedit div.data input, div.mediaedit div.data textarea{ + width: 75%; + padding: 0.1em; + margin: 0.1em; +} + +div.mediaedit div.data input.button { + width: 10em; + display: block; + margin-left: auto; + margin-right: auto; +} + + diff --git a/lib/tpl/default/mediaedit.php b/lib/tpl/default/mediaedit.php new file mode 100644 index 0000000000000000000000000000000000000000..53a969e1b666d195f40f73dc1b9f98ffaac2d0e6 --- /dev/null +++ b/lib/tpl/default/mediaedit.php @@ -0,0 +1,90 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<?php +/** + * DokuWiki Default Template + * + * This is the template for editing image meta data. + * It is displayed in the media popup. + * + * You should leave the doctype at the very top - It should + * always be the very first line of a document. + * + * @link http://wiki.splitbrain.org/wiki:tpl:templates + * @author Andreas Gohr <andi@splitbrain.org> + */ +?> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $conf['lang']?>" lang="<?php echo $conf['lang']?>" dir="ltr"> +<head> + <title><?php echo hsc($lang['mediaselect'])?> [<?php echo hsc($conf['title'])?>]</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <?php tpl_metaheaders()?> + + <link rel="shortcut icon" href="<?php echo DOKU_BASE?>images/favicon.ico" /> + <link rel="stylesheet" media="screen" type="text/css" href="<?php echo DOKU_TPL?>layout.css" /> + <link rel="stylesheet" media="screen" type="text/css" href="<?php echo DOKU_TPL?>design.css" /> +</head> + +<body> +<div class="dokuwiki"> + <?php html_msgarea()?> + + <h1><?php echo hsc($lang['metaedit'])?> <code><?php echo hsc(noNS($IMG))?></code></h1> + + <div class="mediaedit"> + <?php/* everything in meta array is tried to save and read */?> + + <div class="data"> + <form action="<?php echo DOKU_BASE?>lib/exe/media.php" accept-charset="utf-8" method="post"> + <input type="hidden" name="edit" value="<?php echo hsc($IMG)?>" /> + <input type="hidden" name="save" value="1" /> + + <label for="title"><?php echo $lang['img_title']?></label> + <input type="text" name="meta[Iptc.Headline]" id="title" class="edit" + value="<?php echo hsc(tpl_img_getTag('IPTC.Headline'))?>" /><br /> + + <label for="caption"><?php echo $lang['img_caption']?></label> + <textarea name="meta[Iptc.Caption]" id="caption" class="edit" rows="5"><?php + echo hsc(tpl_img_getTag(array('IPTC.Caption', + 'EXIF.UserComment', + 'EXIF.TIFFImageDescription', + 'EXIF.TIFFUserComment'))); + ?></textarea><br /> + + <label for="artist"><?php echo $lang['img_artist']?></label> + <input type="text" name="meta[Iptc.Byline]" id="artist" class="edit" + value="<?php echo hsc(tpl_img_getTag(array('Iptc.Byline', + 'Exif.TIFFArtist', + 'Exif.Artist', + 'Iptc.Credit')))?>" /><br /> + + <label for="copy"><?php echo $lang['img_copyr']?></label> + <input type="text" name="meta[Iptc.CopyrightNotice]" id="copy" class="edit" + value="<?php echo hsc(tpl_img_getTag(array('Iptc.CopyrightNotice','Exif.TIFFCopyright','Exif.Copyright')))?>" /><br /> + + + <label for="keywords"><?php echo $lang['img_keywords']?></label> + <textarea name="meta[Iptc.Keywords]" id="keywords" class="edit"><?php + echo hsc(tpl_img_getTag(array('IPTC.Keywords', + 'EXIF.Category'))); + ?></textarea><br /> + + + <input type="submit" value="<?php echo $lang['btn_save']?>" title="ALT+S" + accesskey="s" class="button" /> + + </form> + </div> + + + <div class="footer"> + <hr> + <?php tpl_button('backtomedia')?> + </div> + </div> + +</div> +</body> +</html> +