/** * If passed path leads to an image, return size * * @param string $Path Path to file. * @return array [0] => Height, [1] => Width. */ public static function GetImageSize($Path) { // Static FireEvent for intercepting non-local files. $Sender = new stdClass(); $Sender->Returns = array(); $Sender->EventArguments = array(); $Sender->EventArguments['Path'] =& $Path; $Sender->EventArguments['Parsed'] = Gdn_Upload::Parse($Path); Gdn::PluginManager()->CallEventHandlers($Sender, 'Gdn_Upload', 'CopyLocal'); if (!in_array(strtolower(pathinfo($Path, PATHINFO_EXTENSION)), array('gif', 'jpg', 'jpeg', 'png'))) { return array(0, 0); } $ImageSize = @getimagesize($Path); if (is_array($ImageSize)) { if (!in_array($ImageSize[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { return array(0, 0); } return array($ImageSize[0], $ImageSize[1]); } return array(0, 0); }
public function Thumbnail($UserReference = '', $Username = '') { $this->Permission('Garden.SignIn.Allow'); $this->AddJsFile('jquery.jcrop.pack.js'); $this->AddJsFile('profile.js'); $Session = Gdn::Session(); if (!$Session->IsValid()) $this->Form->AddError('You must be authenticated in order to use this form.'); $this->GetUserInfo($UserReference, $Username); if ($this->User->UserID != $Session->UserID && !$Session->CheckPermission('Garden.Users.Edit')) throw new Exception(T('You cannot edit the thumbnail of another member.')); $this->Form->SetModel($this->UserModel); $this->Form->AddHidden('UserID', $this->User->UserID); if (!$this->User->Photo) $this->Form->AddError('You must first upload a picture before you can create a thumbnail.'); // Define the thumbnail size $this->ThumbSize = Gdn::Config('Garden.Thumbnail.Size', 32); // Define the source (profile sized) picture & dimensions. $Basename = ChangeBasename($this->User->Photo, 'p%s'); $Upload = new Gdn_UploadImage(); $PhotoParsed = Gdn_Upload::Parse($Basename); $Source = $Upload->CopyLocal($Basename); if (!$Source) { $this->Form->AddError('You cannot edit the thumbnail of an externally linked profile picture.'); } else { $this->SourceSize = getimagesize($Source); } // Add some more hidden form fields for jcrop $this->Form->AddHidden('x', '0'); $this->Form->AddHidden('y', '0'); $this->Form->AddHidden('w', $this->ThumbSize); $this->Form->AddHidden('h', $this->ThumbSize); $this->Form->AddHidden('HeightSource', $this->SourceSize[1]); $this->Form->AddHidden('WidthSource', $this->SourceSize[0]); $this->Form->AddHidden('ThumbSize', $this->ThumbSize); if ($this->Form->AuthenticatedPostBack() === TRUE) { try { // Get the dimensions from the form. Gdn_UploadImage::SaveImageAs( $Source, 'userpics/'.ChangeBasename(basename($this->User->Photo), 'n%s'), $this->ThumbSize, $this->ThumbSize, array('Crop' => TRUE, 'SourceX' => $this->Form->GetValue('x'), 'SourceY' => $this->Form->GetValue('y'), 'SourceWidth' => $this->Form->GetValue('w'), 'SourceHeight' => $this->Form->GetValue('h'))); } catch (Exception $Ex) { $this->Form->AddError($Ex); } // If there were no problems, redirect back to the user account if ($this->Form->ErrorCount() == 0) { Redirect('dashboard/profile/'.$this->ProfileUrl()); } } // Delete the source image if it is externally hosted. if ($PhotoParsed['Type']) { @unlink($Source); } $this->Render(); }
/** * Set user's thumbnail (crop & center photo). * * @since 2.0.0 * @access public * @param mixed $UserReference Unique identifier, possible username or ID. * @param string $Username. */ public function Thumbnail($UserReference = '', $Username = '') { if (!C('Garden.Profile.EditPhotos', TRUE)) { throw ForbiddenException('@Editing user photos has been disabled.'); } // Initial permission checks (valid user) $this->Permission('Garden.SignIn.Allow'); $Session = Gdn::Session(); if (!$Session->IsValid()) { $this->Form->AddError('You must be authenticated in order to use this form.'); } // Need some extra JS // jcrop update jan28, 2014 as jQuery upgrade to 1.10.2 no longer // supported browser() $this->AddJsFile('jquery.jcrop.min.js'); $this->AddJsFile('profile.js'); $this->GetUserInfo($UserReference, $Username, '', TRUE); // Permission check (correct user) if ($this->User->UserID != $Session->UserID && !CheckPermission('Garden.Users.Edit') && !CheckPermission('Moderation.Profiles.Edit')) { throw new Exception(T('You cannot edit the thumbnail of another member.')); } // Form prep $this->Form->SetModel($this->UserModel); $this->Form->AddHidden('UserID', $this->User->UserID); // Confirm we have a photo to manipulate if (!$this->User->Photo) { $this->Form->AddError('You must first upload a picture before you can create a thumbnail.'); } // Define the thumbnail size $this->ThumbSize = Gdn::Config('Garden.Thumbnail.Size', 40); // Define the source (profile sized) picture & dimensions. $Basename = ChangeBasename($this->User->Photo, 'p%s'); $Upload = new Gdn_UploadImage(); $PhotoParsed = Gdn_Upload::Parse($Basename); $Source = $Upload->CopyLocal($Basename); if (!$Source) { $this->Form->AddError('You cannot edit the thumbnail of an externally linked profile picture.'); } else { $this->SourceSize = getimagesize($Source); } // We actually need to upload a new file to help with cdb ttls. $NewPhoto = $Upload->GenerateTargetName('userpics', trim(pathinfo($this->User->Photo, PATHINFO_EXTENSION), '.'), TRUE); // Add some more hidden form fields for jcrop $this->Form->AddHidden('x', '0'); $this->Form->AddHidden('y', '0'); $this->Form->AddHidden('w', $this->ThumbSize); $this->Form->AddHidden('h', $this->ThumbSize); $this->Form->AddHidden('HeightSource', $this->SourceSize[1]); $this->Form->AddHidden('WidthSource', $this->SourceSize[0]); $this->Form->AddHidden('ThumbSize', $this->ThumbSize); if ($this->Form->AuthenticatedPostBack() === TRUE) { try { // Get the dimensions from the form. Gdn_UploadImage::SaveImageAs($Source, ChangeBasename($NewPhoto, 'n%s'), $this->ThumbSize, $this->ThumbSize, array('Crop' => TRUE, 'SourceX' => $this->Form->GetValue('x'), 'SourceY' => $this->Form->GetValue('y'), 'SourceWidth' => $this->Form->GetValue('w'), 'SourceHeight' => $this->Form->GetValue('h'))); // Save new profile picture. $Parsed = $Upload->SaveAs($Source, ChangeBasename($NewPhoto, 'p%s')); $UserPhoto = sprintf($Parsed['SaveFormat'], $NewPhoto); // Save the new photo info. Gdn::UserModel()->SetField($this->User->UserID, 'Photo', $UserPhoto); // Remove the old profile picture. @$Upload->Delete($Basename); } catch (Exception $Ex) { $this->Form->AddError($Ex); } // If there were no problems, redirect back to the user account if ($this->Form->ErrorCount() == 0) { Redirect(UserUrl($this->User, '', 'picture')); $this->InformMessage(Sprite('Check', 'InformSprite') . T('Your changes have been saved.'), 'Dismissable AutoDismiss HasSprite'); } } // Delete the source image if it is externally hosted. if ($PhotoParsed['Type']) { @unlink($Source); } $this->Title(T('Edit My Thumbnail')); $this->_SetBreadcrumbs(T('Edit My Thumbnail'), '/profile/thumbnail'); $this->Render(); }
<?php foreach ($attachments as $attachment) { ?> <?php $isOwner = Gdn::session()->isValid() && Gdn::session()->UserID == $attachment['InsertUserID']; $viewerCssClass = $isOwner ? 'file-owner' : 'file-readonly'; if (Gdn::session()->checkPermission('Garden.Moderation.Manage')) { $viewerCssClass = 'file-owner'; } if (val('InBody', $attachment)) { $viewerCssClass .= ' in-body'; } $pathParse = Gdn_Upload::Parse($attachment['Path']); $thumbPathParse = Gdn_Upload::Parse($attachment['ThumbPath']); $filePreviewCss = $attachment['ThumbPath'] ? '<i class="file-preview img" style="background-image: url(' . $thumbPathParse['Url'] . ')"></i>' : '<i class="file-preview icon icon-file"></i>'; ?> <div class="editor-file-preview <?php echo $viewerCssClass; ?> " id="media-id-<?php echo $attachment['MediaID']; ?> " title="<?php echo htmlspecialchars($attachment['Name']); ?> ">
/** * Saves the specified image at $Target in the specified format with the * specified dimensions (or the existing dimensions if height/width are not * provided. * * @param string The path to the source image. Typically this is the tmp file name returned by $this->ValidateUpload(); * @param string The full path to where the image should be saved, including image name. * @param int An integer value indicating the maximum allowed height of the image (in pixels). * @param int An integer value indicating the maximum allowed width of the image (in pixels). * @param array Options additional options for saving the image. * - <b>Crop</b>: Image proportions will always remain constrained. The Crop parameter is a boolean value indicating if the image should be cropped when one dimension (height or width) goes beyond the constrained proportions. * - <b>OutputType</b>: The format in which the output image should be saved. Options are: jpg, png, and gif. Default is jpg. * - <b>ImageQuality</b>: An integer value representing the qualityof the saved image. Ranging from 0 (worst quality, smaller file) to 100 (best quality, biggest file). * - <b>SourceX, SourceY</b>: If you want to create a thumbnail that is a crop of the image these are the coordinates of the thumbnail. * - <b>SourceHeight. SourceWidth</b>: If you want to create a thumbnail that is a crop of the image these are it's dimensions. */ public static function SaveImageAs($Source, $Target, $Height = '', $Width = '', $Options = array()) { $Crop = FALSE; $OutputType = ''; $ImageQuality = C('Garden.UploadImage.Quality', 75); // Make function work like it used to. $Args = func_get_args(); if (count($Args) > 5) { $Crop = GetValue(4, $Args, $Crop); $OutputType = GetValue(5, $Args, $OutputType); $ImageQuality = GetValue(6, $Args, $ImageQuality); } elseif (is_bool($Options)) { $Crop = $Options; } else { $Crop = GetValue('Crop', $Options, $Crop); $OutputType = GetValue('OutputType', $Options, $OutputType); $ImageQuality = GetValue('ImageQuality', $Options, $ImageQuality); } // Make sure type, height & width are properly defined. if (!function_exists('gd_info')) throw new Exception(T('The uploaded file could not be processed because GD is not installed.')); $GdInfo = gd_info(); $Size = getimagesize($Source); list($WidthSource, $HeightSource, $Type) = $Size; $WidthSource = GetValue('SourceWidth', $Options, $WidthSource); $HeightSource = GetValue('SourceHeight', $Options, $HeightSource); if ($Height == '' || !is_numeric($Height)) $Height = $HeightSource; if ($Width == '' || !is_numeric($Width)) $Width = $WidthSource; if (!$OutputType) { $OutputTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); $OutputType = GetValue($Type, $OutputTypes, 'jpg'); } // Figure out the target path. $TargetParsed = Gdn_Upload::Parse($Target); $TargetPath = PATH_LOCAL_UPLOADS.'/'.ltrim($TargetParsed['Name'], '/'); if (!file_exists(dirname($TargetPath))) mkdir(dirname($TargetPath), 0777, TRUE); // Don't resize if the source dimensions are smaller than the target dimensions $XCoord = GetValue('SourceX', $Options, 0); $YCoord = GetValue('SourceY', $Options, 0); if ($HeightSource > $Height || $WidthSource > $Width) { $AspectRatio = (float) $WidthSource / $HeightSource; if ($Crop === FALSE) { if (round($Width / $AspectRatio) > $Height) { $Width = round($Height * $AspectRatio); } else { $Height = round($Width / $AspectRatio); } } else { $HeightDiff = $HeightSource - $Height; $WidthDiff = $WidthSource - $Width; if ($WidthDiff > $HeightDiff) { // Crop the original width down $NewWidthSource = round(($Width * $HeightSource) / $Height); // And set the original x position to the cropped start point. if (!isset($Options['SourceX'])) $XCoord = round(($WidthSource - $NewWidthSource) / 2); $WidthSource = $NewWidthSource; } else { // Crop the original height down $NewHeightSource = round(($Height * $WidthSource) / $Width); // And set the original y position to the cropped start point. if (!isset($Options['SourceY'])) $YCoord = round(($HeightSource - $NewHeightSource) / 2); $HeightSource = $NewHeightSource; } } } else { // Neither target dimension is larger than the original, so keep the original dimensions. $Height = $HeightSource; $Width = $WidthSource; } // Create GD image from the provided file, but first check if we have the necessary tools $SourceImage = FALSE; switch ($Type) { case 1: if (GetValue('GIF Read Support', $GdInfo) || GetValue('GIF Write Support', $GdInfo)) $SourceImage = imagecreatefromgif($Source); break; case 2: if (GetValue('JPG Support', $GdInfo) || GetValue('JPEG Support', $GdInfo)) $SourceImage = imagecreatefromjpeg($Source); break; case 3: if (GetValue('PNG Support', $GdInfo)) { $SourceImage = imagecreatefrompng($Source); imagealphablending($SourceImage, TRUE); } break; } if (!$SourceImage) throw new Exception(sprintf(T('You cannot save images of this type (%s).'), $Type)); // Create a new image from the raw source if (function_exists('imagecreatetruecolor')) { $TargetImage = imagecreatetruecolor($Width, $Height); // Only exists if GD2 is installed } else $TargetImage = imagecreate($Width, $Height); // Always exists if any GD is installed if ($OutputType == 'png') { imagealphablending($TargetImage, FALSE); imagesavealpha($TargetImage, TRUE); } imagecopyresampled($TargetImage, $SourceImage, 0, 0, $XCoord, $YCoord, $Width, $Height, $WidthSource, $HeightSource); imagedestroy($SourceImage); // No need to check these, if we get here then whichever function we need will be available if ($OutputType == 'gif') imagegif($TargetImage, $TargetPath); else if ($OutputType == 'png') { imagepng($TargetImage, $TargetPath, (int)($ImageQuality/10)); } else imagejpeg($TargetImage, $TargetPath, $ImageQuality); // Allow a plugin to move the file to a differnt location. $Sender = new stdClass(); $Sender->EventArguments = array(); $Sender->EventArguments['Path'] = $TargetPath; $Parsed = self::Parse($TargetPath); $Sender->EventArguments['Parsed'] =& $Parsed; $Sender->Returns = array(); Gdn::PluginManager()->CallEventHandlers($Sender, 'Gdn_UploadImage', 'SaveImageAs'); return $Sender->EventArguments['Parsed']; }
/** * Delete an uploaded file & its media record. * * @access protected * @param int $MediaID Unique ID on Media table. */ protected function TrashFile($MediaID) { $Media = $this->MediaModel()->GetID($MediaID); if ($Media) { $this->MediaModel()->Delete($Media); $Deleted = FALSE; // Allow interception $this->EventArguments['Parsed'] = Gdn_Upload::Parse($Media->Path); $this->EventArguments['Handled'] =& $Deleted; // Allow skipping steps below $this->FireEvent('TrashFile'); if (!$Deleted) { $DirectPath = MediaModel::PathUploads() . DS . $Media->Path; if (file_exists($DirectPath)) { $Deleted = @unlink($DirectPath); } } if (!$Deleted) { $CalcPath = FileUploadPlugin::FindLocalMedia($Media, TRUE, TRUE); if (file_exists($CalcPath)) { $Deleted = @unlink($CalcPath); } } } }