public static StreamInfo RetrievePreview(ResourceBE attachment, uint height, uint width, RatioType ratio, SizeType size, FormatType format, out string filename) { if (!AttachmentBL.Instance.IsAllowedForImageMagickPreview(attachment)) { throw new AttachmentPreviewFailedWithMimeTypeNotImplementedException(attachment.MimeType); } if (format != FormatType.UNDEFINED && size != SizeType.UNDEFINED && size != SizeType.ORIGINAL && size != SizeType.CUSTOM) { throw new AttachmentPreviewFormatConversionWithSizeNotImplementedException(); } // check that attachment has a width and height defined AttachmentBL.Instance.IdentifyUnknownImages(new ResourceBE[] { attachment }); #region check validity of size, width, and height parameters // NOTE (steveb): following table describes the possible state-transitions; note that the resulting graph must acyclic to avoid infinite loops. // BESTFIT // -> THUMB // -> WEBVIEW // -> ORIGINAL // UNDEFINED // -> CUSTOM // -> ORIGINAL // THUMB // -> ORIGINAL // WEBVIEW // -> ORIGINAL // CUSTOM // -> ORIGINAL // ORIGINAL again: switch (size) { case SizeType.BESTFIT: if (width == 0 && height == 0) { // no dimensions specified, use original size = SizeType.ORIGINAL; goto again; } if (width <= DekiContext.Current.Instance.ImageThumbPixels && height <= DekiContext.Current.Instance.ImageThumbPixels) { // thumbnail is big enough size = SizeType.THUMB; goto again; } else if (width <= DekiContext.Current.Instance.ImageWebviewPixels && height <= DekiContext.Current.Instance.ImageWebviewPixels) { // webview is big enough size = SizeType.WEBVIEW; goto again; } else { // use original size = SizeType.ORIGINAL; goto again; } case SizeType.CUSTOM: if (height == 0 && width == 0) { // no dimensions specified, use original size = SizeType.ORIGINAL; goto again; } if ((attachment.MetaXml.ImageWidth <= width && attachment.MetaXml.ImageHeight <= height) && (attachment.MetaXml.ImageWidth >= 0 && attachment.MetaXml.ImageHeight >= 0)) { // requested dimensions are larger than original, use original (we don't scale up!) size = SizeType.ORIGINAL; goto again; } break; case SizeType.ORIGINAL: width = 0; height = 0; break; case SizeType.UNDEFINED: if (height != 0 || width != 0) { size = SizeType.CUSTOM; goto again; } else { size = SizeType.ORIGINAL; goto again; } case SizeType.THUMB: width = DekiContext.Current.Instance.ImageThumbPixels; height = DekiContext.Current.Instance.ImageThumbPixels; if ((attachment.MetaXml.ImageWidth <= width && attachment.MetaXml.ImageHeight <= height) && (attachment.MetaXml.ImageWidth >= 0 && attachment.MetaXml.ImageHeight >= 0)) { size = SizeType.ORIGINAL; goto again; } break; case SizeType.WEBVIEW: width = DekiContext.Current.Instance.ImageWebviewPixels; height = DekiContext.Current.Instance.ImageWebviewPixels; if ((attachment.MetaXml.ImageWidth <= width && attachment.MetaXml.ImageHeight <= height) && (attachment.MetaXml.ImageWidth >= 0 && attachment.MetaXml.ImageHeight >= 0)) { size = SizeType.ORIGINAL; goto again; } break; } #endregion // Asking to convert to the same format as original if (format != FormatType.UNDEFINED && format == ResolvePreviewFormat(attachment.MimeType)) { format = FormatType.UNDEFINED; } //Determine if the result is capable of being cached bool cachable = ( format == FormatType.UNDEFINED && //No format conversion ratio != RatioType.VARIABLE && //must be a fixed aspect ratio or not provided (size == SizeType.THUMB || size == SizeType.WEBVIEW) //must be one of the known cached thumb sizes. ); // load image StreamInfo result = null; try { if (size == SizeType.ORIGINAL && format == FormatType.UNDEFINED) { result = DekiContext.Current.Instance.Storage.GetFile(attachment, SizeType.ORIGINAL, false); } else { bool cached = false; //The type of image is based on uploaded file's mimetype if (format == FormatType.UNDEFINED) { format = ResolvePreviewFormat(attachment.MimeType); } // check if image can be taken from the cache if (cachable) { result = GetCachedThumb(attachment, size); cached = (result != null); } // load image if we haven't yet if (result == null) { result = DekiContext.Current.Instance.Storage.GetFile(attachment, SizeType.ORIGINAL, false); if (result != null) { result = BuildThumb(attachment, result, format, ratio, width, height); } } // store result if possible and needed if (cachable && !cached && (result != null)) { SaveCachedThumb(attachment, size, result); result = GetCachedThumb(attachment, size); } } if (result == null) { ThrowOnBadPreviewImage(); } // full filename for response content-disposition header switch (size) { case SizeType.CUSTOM: filename = string.Format("{0}_({1}x{2}){3}", attachment.Name, width == 0 ? "" : width.ToString(), height == 0 ? "" : height.ToString(), attachment.FilenameExtension == string.Empty ? string.Empty : "." + attachment.FilenameExtension); break; case SizeType.ORIGINAL: filename = attachment.Name; break; case SizeType.BESTFIT: case SizeType.THUMB: case SizeType.UNDEFINED: case SizeType.WEBVIEW: default: filename = string.Format("{0}_({1}){2}", attachment.Name, size.ToString().ToLowerInvariant(), attachment.FilenameExtension == string.Empty ? string.Empty : "." + attachment.FilenameExtension); break; } if (format != FormatType.UNDEFINED) { filename = Path.ChangeExtension(filename, format.ToString().ToLowerInvariant()); } return(result); } catch { if (result != null) { result.Close(); } throw; } }