The Jpeg Class
This is the main workhorse of the application.
It handles all resizing and metadata operations
You can load it from a file on your disk or from an uploaded file stream. Here we load it from a file uploaded in a photo model
You call it like this…
using (Jpeg jpeg = new Jpeg(model.UploadedFile))
{
// EDIT TO MEET YOUR NEEDS
jpeg.Copyright = "www.bennysutton.com";
jpeg.Creator = photo.Creator;
jpeg.Country = "country not set";
jpeg.Headline = "headline not set";
jpeg.Keywords = photo.Keywords;
jpeg.Software = "ADz";
jpeg.Subject = photo.Description;
jpeg.Title = "Title not set";
jpeg.Save(“~/images/”);
jpeg.ResizeAndSave(
"~/P/photos/thumbs/",
photo.Id.ToString() + ".jpg",
100);
jpeg.ResizeAndSave(
"~/P/photos/zoom/",
photo.Id.ToString() + ".jpg",
300);
jpeg.ResizeAndSave(
"~/P/photos/",
photo.Id.ToString() + ".jpg",
600);
}
using ImageMagick;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
namespace Ben.Classes
{
///
/// A class that takes a png/gif/jpg and automatically saves it to the only filetype you'll ever need - jpeg.
/// A wrapper class for ImageMagick that gets the important stuff
/// from an image file's metadata so that you can do neat sh*t with it!
///
/// free to use - distributed under the [MIT License](Learn more at http://opensource.org/licenses/mit-license.php):
/// Requires Ben.Classes.ExtensionHelpers
///
/// https://www.bennysutton.com/
///
public class Jpeg : IDisposable
{
private MagickImage _image;
private string _keywords;
///
/// load from an image file on your hard disk
///
/// root relative virtual path to the script or path for the current request e.g. ~/admin/imagename.jpg or /admin/imagename.jpg
public Jpeg(string rootpath)
{
// prevent accidental reloading on top of existing
if (!_image.IsNull()) throw new Exception("Image already loaded");
if (!rootpath.GetFileName().IsImage()) throw new Exception("File does not have an image file extension");
if (!File.Exists(rootpath.PhysicalPathFromRootPath())) throw new Exception("The file specified to load does not exist");
Source = rootpath.GetFileName();
_image = new MagickImage(rootpath.PhysicalPathFromRootPath());
Init();
}
///
/// load from another MagickImage image
///
///
public Jpeg(MagickImage image)
{
// prevent accidental reloading on top of existing
if (!_image.IsNull()) throw new Exception("Image already loaded");
if (!image.FileName.IsImage()) throw new Exception("File does not have an image file extension");
Source = image.FileName;
_image = image;
Init();
}
///
/// load an image (png/gif/jpg format) from a file upload
///
/// an image file uploaded from a client
public Jpeg(HttpPostedFileBase httpPostedFile)
{
// prevent accidental reloading on top of existing
if (!_image.IsNull()) throw new Exception("Image already loaded");
if (!httpPostedFile.FileName.GetFileName().IsImage()) throw new Exception("File does not have an image file extension");
try
{
Source = httpPostedFile.FileName.GetFileName();
_image = new MagickImage(httpPostedFile.InputStream);
Init();
}
catch
{
throw;
}
}
///
/// persist existing metadata values (if any) to property values
///
private void Init()
{
IExifProfile exifprofile = _image.GetExifProfile();
if (exifprofile != null)
{
if (exifprofile.GetValue(ExifTag.Copyright) != null) { Copyright = exifprofile.GetValue(ExifTag.Copyright).ToString(); }
if (exifprofile.GetValue(ExifTag.Artist) != null) { Creator = exifprofile.GetValue(ExifTag.Artist).ToString(); }
if (exifprofile.GetValue(ExifTag.ImageDescription) != null) { Subject = exifprofile.GetValue(ExifTag.ImageDescription).ToString(); }
if (exifprofile.GetValue(ExifTag.Software) != null) { Software = exifprofile.GetValue(ExifTag.Software).ToString(); }
}
IIptcProfile iptcprofile = _image.GetIptcProfile();
if (iptcprofile != null)
{
if (iptcprofile.GetValue(IptcTag.Country) != null) { Country = iptcprofile.GetValue(IptcTag.Country).ToString(); }
if (iptcprofile.GetValue(IptcTag.Headline) != null) { Headline = iptcprofile.GetValue(IptcTag.Headline).ToString(); }
if (iptcprofile.GetValue(IptcTag.Keyword) != null) { Keywords = iptcprofile.GetValue(IptcTag.Keyword).ToString(); }
if (iptcprofile.GetValue(IptcTag.Source) != null) { Source = iptcprofile.GetValue(IptcTag.Source).ToString(); }
if (iptcprofile.GetValue(IptcTag.Caption) != null) { Subject = iptcprofile.GetValue(IptcTag.Caption).ToString(); }
if (iptcprofile.GetValue(IptcTag.Title) != null) { Title = iptcprofile.GetValue(IptcTag.Title).ToString(); }
}
}
public bool Save(string rootpath)
{
bool success = false;
ImageMagick.ExifProfile exifprofile = new ImageMagick.ExifProfile();
exifprofile.SetValue(ExifTag.Copyright, " ©" + Copyright);
exifprofile.SetValue(ExifTag.Artist, Creator);
exifprofile.SetValue(ExifTag.ImageDescription, Subject);
exifprofile.SetValue(ExifTag.Software, Software);
_image.AddProfile(exifprofile);
ImageMagick.IptcProfile iptcprofile = new ImageMagick.IptcProfile();
iptcprofile.SetValue(IptcTag.CopyrightNotice, "No Unauthorized reproduction ©" + Copyright);
iptcprofile.SetValue(IptcTag.Byline, Creator);
iptcprofile.SetValue(IptcTag.Country, Country);
iptcprofile.SetValue(IptcTag.Headline, Headline);
iptcprofile.SetValue(IptcTag.Keyword, Keywords);
iptcprofile.SetValue(IptcTag.Source, Source);
iptcprofile.SetValue(IptcTag.Caption, Subject);
iptcprofile.SetValue(IptcTag.Title, Title);
_image.AddProfile(iptcprofile);
_image.Write(rootpath);
success = true;
return success;
}
///
/// Save the image to a JPEG
///
/// Optionally resize the image to a value between 100 and 3000 pixels (longest side)
/// the virtual path on the server to save to e.g. "~/images/"
/// the name of the file that you want to save to (including ".jpg" extension)
/// allow/stop overwriting of existing file
/// requires Ben.ExtensionHelpers
public void ResizeAndSave(string rootpathToSaveTo, string fileName, int resizeTo = 0, bool overWrite = true)
{
// validation of parameters passed in and check path related constraints
// bit of a code smell here but validation code below only happens in this method so do not refactor for now...
string physicalSaveToFolder = rootpathToSaveTo.PhysicalPathFromRootPath(); // convert virtual website path to server file system path
if (!Directory.Exists(physicalSaveToFolder)) throw new Exception("The directory specified to save to does not exist");
fileName = string.Join("", fileName.Split(Path.GetInvalidFileNameChars())); // remove any accidentally passed in characters that are illegal in a filename e.g. / \ [ ] : ; | , ?
Path.ChangeExtension(fileName, "jpg"); // ensure the filename is jpeg compliant - needed for the automatic encoder later
string filepath = Path.Combine(physicalSaveToFolder, fileName);
if (overWrite = false && File.Exists(filepath)) throw new Exception("This would overwrite an existing file"); // to stop overwriting of existing file if parameter overwite = false
// resize image to max number of pixels longest side
// limit minimum and maximum file dimensions
if (resizeTo >= 1 && !Enumerable.Range(100, 3000).Contains(resizeTo)) throw new Exception("The file size specified to save to must be between 100px and 3000px");
var size = _image.Height <= _image.Width
? new MagickGeometry(resizeTo, 0)
: new MagickGeometry(0, resizeTo);
size.IgnoreAspectRatio = false;
MagickImage clone = new MagickImage(_image);
clone.Resize(size);
clone.Write(filepath);
}
///
/// resets Keywords - when you add keywords with multiple calls to Keyword they are preserved so this is the only way to reset them - don't forget to call Save() afterwards
///
public void ClearKeywords()
{
_keywords = "";
}
///
/// Allows you to loop through all the fields e.g. on a razor page
///
/// Ben.Classes.Jpeg magickMetadata = new Ben.Classes.Jpeg(filename);
/// Dictionary myDictionary = magickMetadata.ClassPropertiesToDictionary();
/// a dictionary of field names and values
public Dictionary ClassPropertiesToDictionary()
{
return this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(this, null));
}
#region AutoImplementedProperties
///
/// used to show copyright notice NOTE the copyright symbol © gets automatically prepended
///
public string Copyright { get; set; }
///
/// use to show the name of the person who took the photo and/or user who uploaded
///
public string Creator { get; set; }
public string Country { get; set; }
public string Headline { get; set; }
///
/// Keywords NOTE if you call multiple times values will be appended not overwritten - call KeywordsClear() to reset
///
public string Keywords
{
get
{
return _keywords;
}
set
{
if (String.IsNullOrEmpty(_keywords))
{
_keywords = value;
}
else
{
_keywords = _keywords + " " + value;
}
}
}
public string Software { get; set; }
public string Source { get; internal set; }
public string Subject { get; set; }
public string Title { get; set; }
#endregion
// DISPOSE
public void Dispose()
{
_image.Dispose();
}
}
}
Next >>>