/// <summary> /// Save the kraked image to a specific Umbraco Media node /// </summary> /// <param name="imKrakTarget">Target media node</param> /// <param name="keepOriginal">Save the original image in Umbraco? Pass NULL to use global settings</param> /// <param name="hasChanged">Has a new image been selected for the media node just now?</param> /// <returns>Success status</returns> internal bool Save(Media mKrakTarget, bool?keepOriginal = null, bool hasChanged = false) { umbraco.cms.businesslogic.property.Property p; // Validate parameters var status = GetKrakStatus(mKrakTarget); if (status == EnmIsKrakable.Unkrakable || status == EnmIsKrakable.Original || String.IsNullOrEmpty(kraked_url)) { // This image is unkrakable, do not proceed return(false); } // Determine the path and the name of the image var relativeFilepath = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasFile).Value.ToString(); var relativeDirectory = System.IO.Path.GetDirectoryName(relativeFilepath); var absoluteDirectory = System.Web.Hosting.HostingEnvironment.MapPath("~" + relativeDirectory); string filename = Path.GetFileName(relativeFilepath); if (keepOriginal == null) { keepOriginal = Configuration.Settings.KeepOriginal; } // Has this media node already been Kraked before? int originalSize = 0; if (status == EnmIsKrakable.Kraked) { p = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasOriginalSize); if (p != null && p.Value != null) { int.TryParse(p.Value.ToString(), out originalSize); } } if (originalSize == 0) { originalSize = original_size; } var compressionRate = (((decimal)(originalSize - kraked_size)) / originalSize).ToString("p2"); // The following might seem redundant, but Umbraco's "SetValue" extension method used below actually does a lot of magic for us. // However, Umbraco will also create a new media folder for us to contain the new image which we do NOT want (the url to the image has to remain unchanged). // So some extra efforts are required to make sure the compressed image will be switched in the place of the original image. var originalUmbracoFilePropertyData = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasFile).Value.ToString(); // Get the original property data if (!mKrakTarget.AddFile(kraked_url, filename)) { return(false); // Krak failed } // Extract the absolute directory path var newRelativeFilepath = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasFile).Value.ToString(); // Retrieve the relative filepath to the new image location var newRelativeDirectory = System.IO.Path.GetDirectoryName(newRelativeFilepath); // Extract the relative directoryname var newAbsoluteDirectory = System.Web.Hosting.HostingEnvironment.MapPath("~" + newRelativeDirectory); // Convert to it's absolute variant mKrakTarget.getProperty(Constants.UmbracoPropertyAliasFile).Value = originalUmbracoFilePropertyData; // Put the original property data back in place // If an "original" media node is already present under the current node, then save our original data to that node. // Else we will keep creating new nodes under the current node each time we save, and we never want more then 1 original node! var mOriginal = mKrakTarget.Children.FirstOrDefault(x => x.Text == EnmKrakStatus.Original.ToString() && x.getProperty(Constants.UmbracoPropertyAliasStatus) != null && x.getProperty(Constants.UmbracoPropertyAliasStatus).Value as String == "Original"); // Does the original media node already exist? bool originalExists = mOriginal != null; // Do we need to keep a backup of the originally kraked image? if (keepOriginal.Value) { if (!originalExists) { // No. Simply create a new "Original" media node under the current node, which will be used to store our "backup" mOriginal = Media.MakeNew(EnmKrakStatus.Original.ToString(), MediaType.GetByAlias(mKrakTarget.ContentType.Alias), mKrakTarget.User, mKrakTarget.Id); } // We are only allowed to MODIFY the ORIGINAL media node if the FILE has CHANGED! If the original file has not been modified, then we are ONLY allowed to create a NEW media node (aka it didn't exist before) if (hasChanged || !originalExists) { // Copy all properties of the current media node to the original (aka: BACKUP) foreach (var p2 in mOriginal.GenericProperties) { p2.Value = mKrakTarget.getProperty(p2.PropertyType.Alias).Value; } // The image has been modified during the saving proces before, so correct that by specifying the correct original imag p = mOriginal.getProperty(Constants.UmbracoPropertyAliasFile); if (p != null) { // Save the original data, but replace the old relative filepath with the new one p.Value = originalUmbracoFilePropertyData.Replace(relativeFilepath, newRelativeFilepath); } // The same for filesize p = mOriginal.getProperty(Constants.UmbracoPropertyAliasSize); if (p != null) { p.Value = originalSize; } // Set the "status" of the original image to "Original", so we know in the future this is the original image p = mOriginal.getProperty(Constants.UmbracoPropertyAliasStatus); if (p != null) { p.Value = EnmKrakStatus.Original.ToString(); } // Save the original node. It will be placed directly underneath the current media node mOriginal.Save(); // Now swap the folders so everything is correct again string tmpFolder = absoluteDirectory + "_tmp"; System.IO.Directory.Move(absoluteDirectory, tmpFolder); System.IO.Directory.Move(newAbsoluteDirectory, absoluteDirectory); System.IO.Directory.Move(tmpFolder, newAbsoluteDirectory); } else { // Leave the original alone! So just replace the target folder with the compressed version if (System.IO.Directory.Exists(absoluteDirectory)) { System.IO.Directory.Delete(absoluteDirectory, true); } System.IO.Directory.Move(newAbsoluteDirectory, absoluteDirectory); } } else { if (originalExists) { var originalFilePath = mOriginal.getProperty(Constants.UmbracoPropertyAliasFile).Value.ToString(); var originalRelativeDirectory = System.IO.Path.GetDirectoryName(originalFilePath); var originalAbsoluteDirectory = System.Web.Hosting.HostingEnvironment.MapPath("~" + originalRelativeDirectory); mOriginal.delete(true); if (System.IO.Directory.Exists(originalAbsoluteDirectory)) { System.IO.Directory.Delete(originalAbsoluteDirectory, true); } } if (System.IO.Directory.Exists(absoluteDirectory)) { System.IO.Directory.Delete(absoluteDirectory, true); } System.IO.Directory.Move(newAbsoluteDirectory, absoluteDirectory); } // Show the original size p = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasOriginalSize); if (p != null) { p.Value = originalSize; } // Show the kraked status p = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasStatus); if (p != null) { p.Value = EnmKrakStatus.Compressed.ToString(); } // Show the kraked date p = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasCompressionDate); if (p != null) { p.Value = DateTime.Now.ToString(); } // Show how many bytes we by kraking the image p = mKrakTarget.getProperty(Constants.UmbracoPropertyAliasSaved); if (p != null) { p.Value = compressionRate; } // Save the newly (kraked) media item mKrakTarget.Save(); // Clean up the cache HttpRuntime.Cache.Remove("kraken_" + id); HttpRuntime.Cache.Remove("kraken_" + id + "_user"); // W 8-1-2016: Obsolete as the media URL should never change in the first place // Refresh the Umbraco Media cache (else you might end up getting the old media node URL when fetching the filename) //Umbraco.Web.Cache.DistributedCache.Instance.Refresh(new Guid(Umbraco.Web.Cache.DistributedCache.MediaCacheRefresherId), imKrakTarget.Id); return(true); }