/** * Render markup for an image tag in smarty * * The {img} smarty function is the recommended way to load images in templates from asset or public directories. * In addition to automatically resolving URLs, it can also handle server-side resizing and a few other nifty features. * * #### Image Types & Animations * * As of Core 3.3.0, image types are preserved, so if a .jpg is requested, an image/jpeg is returned. * This changed from the previous behaviour where all images were converted to a PNG. * * Supported image types are `.jp[e]g`, `.png`, and `.gif`. * * If an animated gif is resized, the server will attempt to preserve the animation on the resized image. * This is done via imagemagick, (so that library needs to be present on the server in order for this trick to work). * * #### SEO Data * * As of Core 3.2.0, alt tags are automatically added to every image that does not have the alt attribute explicitly set. * This alt name is pulled from the filename of the image, with automatic capitalization and '_' => (space) converting. * * #### Smarty Parameters * * * assign * * string * * Set to a string to assign that variable name instead of returning the output. * * dimensions * * Provide both width and height in pixels, along with special instructions * * Structure is "widthxheight" with no spaces between the "x" and the two integers. * * Special modes available are: * * Carat "`^`" at the end of the string fits the smallest dimension instead of the largest. * * Exclamation mark "`!`" at the end forces size regardless of aspect ratio. * * Greater than "`>`" at the end will only increase image sizes. * * Less than "`<`" at the end will only decrease image sizes. * * file * * \Core\Filestore\File * * File object passed in to display * * Either "file" or "src" is required. * * height * * int * * Maximum image height (in pixels). * * If both width and height are provided, the image will be constrained to both without any distortion. * * inline * * int "1" or "0", (default "0") * * New in Core 4.2.0 * * Request that the resized image be encoded as base64 and inserted inline in the markdown instead of returned as the URL. * * placeholder * * string * * placeholder image if the requested image is blank or not found. Useful for optional fields that should still display something. * * Current values: "building", "generic", "person", "person-tall", "person-wide", "photo" * * src * * string * * Source filename to display. This can start with "assets" for an asset, or "public" for a public file. * * Either "file" or "src" is required. * * width * * int * * Maximum image width (in pixels). * * If both width and height are provided, the image will be constrained to both without any distortion. * * Any other parameter is transparently sent to the resulting `<img/>` tag. * * * #### Example Usage * * <pre> * {img src="public/gallery/photo123.png" width="123" height="123" placeholder="photo" alt="My photo 123"} * </pre> * * @param array $params Associative (and/or indexed) array of smarty parameters passed in from the template * @param Smarty $smarty Parent Smarty template object * * @return string * @throws SmartyException */ function smarty_function_img($params, $smarty){ // Key/value array of attributes for the resulting HTML. $attributes = array(); if(isset($params['file'])){ $f = $params['file']; if(!$f instanceof \Core\Filestore\File){ throw new SmartyException('{img} tag expects a \Core\Filestore\File object for the "file" parameter.'); } unset($params['file']); } elseif(isset($params['src'])){ $f = \Core\Filestore\Factory::File($params['src']); unset($params['src']); } else{ $f = null; } // Some optional parameters, (and their defaults) $assign = $width = $height = $dimensions = $inline = false; $placeholder = $previewfile = null; if(isset($params['assign'])){ $assign = $params['assign']; unset($params['assign']); } if(isset($params['width'])){ $width = $params['width']; unset($params['width']); } if(isset($params['height'])){ $height = $params['height']; unset($params['height']); } if(isset($params['dimensions'])){ $dimensions = $params['dimensions']; $width = preg_replace('#[^0-9]?([0-9]*)x.*#', '$1', $dimensions); $height = preg_replace('#.*x([0-9]*)[^0-9]?#', '$1', $dimensions); unset($params['dimensions']); } if(isset($params['placeholder'])){ $placeholder = $params['placeholder']; unset($params['placeholder']); } if(isset($params['inline'])){ $inline = ($params['inline'] == '1'); unset($params['inline']); } if($dimensions){ // Passing in dimensions raw will allow the user more control over the size of the images. $d = $dimensions; } else{ // If one is provided but not the other, just make them the same. if($width && !$height) $height = $width; if($height && !$width) $width = $height; $d = ($width && $height) ? $width . 'x' . $height : false; } // If the file doesn't exist and a placeholder was provided, use the appropriate placeholder image! if(!($f && $f->exists() && $f->isImage()) && $placeholder){ // Try that! $f = \Core\Filestore\Factory::File('assets/images/placeholders/' . $placeholder . '.png'); } if(!$f){ throw new SmartyException('{img} tag requires either "src", "file", or a "placeholder" parameter.'); } // Do the rest of the attributes that the user sent in (if there are any) foreach($params as $k => $v){ $attributes[$k] = $v; } if($f instanceof Core\Filestore\Backends\FileRemote){ // Erm... Give the original URL with the dimension requests. $attributes['src'] = $f->getURL(); if($width) $attributes['width'] = $width; if($height) $attributes['height'] = $height; } else{ // Try to lookup the preview file. // if it exists, then YAY... I can return that direct resource. // otherwise, I should check and see if the file is larger than a set filesize. // if it is, then I want to return a link to a controller to render that file instead of rendering the file from within the {img} tag. // // This is useful because any logic contained within this block will halt page execution! // To improve the perception of performance, that can be offloaded to the browser requesting the <img/> contents. $previewfile = $d ? $f->getQuickPreviewFile($d) : $f; if(!$previewfile){ $attributes['src'] = '#'; $attributes['title'] = 'No preview files available!'; } elseif($inline && $f->getFilesize() < 1048576*4){ // Overwrite the src attribute with the base64 contents. // This can only happen after the preview file exists! if(!$previewfile->exists()){ // Since quick ran, ensure that it's actually resized! $previewfile = $f->getPreviewFile($d); } $attributes['src'] = 'data:' . $previewfile->getMimetype() . ';base64,' . base64_encode($previewfile->getContents()); } elseif(!$previewfile->exists()){ // Ok, it doesn't exist... return a link to the controller to render this file. $attributes['src'] = \Core\resolve_link('/file/preview') . '?f=' . $f->getFilenameHash() . '&d=' . $d; } else{ $attributes['src'] = $previewfile->getURL(); } } // All images need alt data! if(!isset($attributes['alt'])){ $attributes['alt'] = $f->getTitle(); } // Merge them back together in one string. $html = '<img'; foreach($attributes as $k => $v) $html .= " $k=\"$v\""; $html .= '/>'; // If the extended metadata was requested... look that up too! if(isset($params['includemeta']) && $params['includemeta']){ $metahelper = new \Core\Filestore\FileMetaHelper($f); $metacontent = $metahelper->getAsHTML(); if($metacontent){ $html = '<div class="image-metadata-wrapper">' . $html . $metacontent . '</div>'; } } return $assign ? $smarty->assign($assign, $html) : $html; }
public static function ImagesUpdateSaveHandler(Form $form) { try { /** @var $image GalleryImageModel */ $image = $form->getModel('image'); } catch (Exception $e) { Core::SetMessage($e->getMessage(), 'error'); return false; } $metas = new \Core\Filestore\FileMetaHelper($image->getOriginalFile()); // Set the meta information from the form. foreach ($form->getElements() as $el) { /** @var $el FormElement */ $name = $el->get('name'); if (strpos($name, 'metas[') !== 0) { continue; } $name = substr($name, 6, -1); $metas->setMeta($name, $el->get('value')); } // If no title was set, I need to pick one by default. if (!$metas->getMetaTitle('title')) { // Generate a moderately meaningful title from the filename. $title = $image->getOriginalFile()->getBasename(true); $title = preg_replace('/[^a-zA-Z0-9 ]/', ' ', $title); $title = trim(preg_replace('/[ ]+/', ' ', $title)); $title = ucwords($title); $metas->setMeta('title', $title); } if (!$image->exists()) { // Figure out the largest weight of this album. // Note, this is NOT the size of the images, as one or more may have been deleted after uploading. $last = GalleryImageModel::Find(array('albumid' => $image->get('albumid')), 1, 'weight DESC'); $weight = $last ? $last->get('weight') : 0; $image->set('weight', $weight); } // Don't forget to keep the metatags in sync! $image->set('title', $metas->getMetaTitle('title')); $action = $image->exists() ? 'Updated' : 'Added'; $image->save(); Core::SetMessage($action . ' image successfully!', 'success'); return true; }
/** * Utility to Core-ify a given HTML string. * * Will use a tokenizer to scan for <img /> tags and <a /> tags. * * @param $html * @return string */ function parse_html($html){ // Counter for the current position of the tokenizer. $x = 0; // Set to the position of the current image $imagestart = null; // @todo a rel=nofollow tags for external/untrusted links // This can make use of an external utility to allow the admin to set which links are allowed. // @todo a tags that are absolutely resolved or have a core prefix such as core:///about-us or what not. while($x < strlen($html)){ // Replace images with the optimized version. if(substr($html, $x, 4) == '<img'){ $imagestart = $x; $x+= 3; continue; } $fullimagetag = null; if($imagestart !== null && $html{$x} == '>'){ // This will equal the full image HTML tag, ie: <img src="blah"/>... $fullimagetag = substr($html, $imagestart, $x-$imagestart+1); } elseif($imagestart !== null && substr($html, $x, 2) == '/>'){ // This will equal the full image HTML tag, ie: <img src="blah"/>... $fullimagetag = substr($html, $imagestart, $x-$imagestart+2); } if($imagestart !== null && $fullimagetag){ // Convert it to a DOM element so I can process it. $simple = new \SimpleXMLElement($fullimagetag); $attributes = array(); foreach($simple->attributes() as $k => $v){ $attributes[$k] = (string)$v; } $file = \Core\Filestore\Factory::File($attributes['src']); // All images need alt tags. if(!isset($attributes['alt']) || $attributes['alt'] == ''){ // Since this is usually only used to render content and the images contained therein, // and tinymce auto-adds a blank alt="" attribute, // I can safely add the alt based on the file's rendered title. $attributes['alt'] = $file->getTitle(); } if(isset($attributes['width']) || isset($attributes['height'])){ if(isset($attributes['width']) && isset($attributes['height'])){ $dimension = $attributes['width'] . 'x' . $attributes['height'] . '!'; unset($attributes['width'], $attributes['height']); } elseif(isset($attributes['width'])){ $dimension = $attributes['width']; unset($attributes['width']); } else{ $dimension = $attributes['height']; unset($attributes['height']); } $attributes['src'] = $file->getPreviewURL($dimension); } // And rebuild. $img = '<img'; foreach($attributes as $k => $v){ $img .= ' ' . $k . '="' . str_replace('"', '"', $v) . '"'; } $img .= '/>'; $metahelper = new \Core\Filestore\FileMetaHelper($file); $metacontent = $metahelper->getAsHTML(); if($metacontent){ $img = '<div class="image-metadata-wrapper">' . $img . $metacontent . '</div>'; } // Figure out the offset for X. I'll need to modify this after I merge it in. $x += strlen($img) - strlen($fullimagetag); // Split this string back in. $html = substr_replace($html, $img, $imagestart, strlen($fullimagetag)); // Reset... $imagestart = null; } $x++; } //var_dump($html); return $html; }
/** * Save handler for the form_metadata page. * * @param Form $form */ public static function FileMetadataSaveHandler(Form $form) { $filename = $form->getElement('file')->get('value'); $file = \Core\Filestore\Factory::File($filename); $helper = new \Core\Filestore\FileMetaHelper($file); // Run through each element and save its metadata to the table. foreach ($form->getElements() as $el) { /** @var $el FormElement */ $name = $el->get('name'); if ($name == 'file') { continue; } if ($name == '___formid') { continue; } if ($name == 'submit') { continue; } $helper->setMeta($name, $el->get('value')); } return true; }
/** * Created by JetBrains PhpStorm. * User: powellc * Date: 1/17/13 * Time: 10:20 PM * This is the upgrade file from 1.4.3 to 1.4.4 * * Required because with the file input change in 2.6.0 returning core resolved paths, * the data in the database will contain that path now. */ $images = GalleryImageModel::Find(); foreach ($images as $i) { /** @var $i GalleryImageModel */ // Just in case if (strpos($i->get('file'), 'public/') !== 0) { $i->set('file', 'public/galleryalbum/' . $i->get('file')); $i->save(); } // Don't forget to copy over the meta data too! // This is because the gallery system will use the new version of metadata. $u = UserModel::Construct($i->get('uploaderid')); $helper = new \Core\Filestore\FileMetaHelper($i->getOriginalFile()); $helper->setMeta('title', $i->get('title')); $helper->setMeta('keywords', explode(',', $i->get('keywords'))); $helper->setMeta('description', $i->get('description')); $helper->setMeta('authorid', $i->get('uploaderid')); if ($u && $u instanceof User_Backend) { $helper->setMeta('author', $u->getDisplayName()); } }