public ViewModel(IMainUI mainUI, IColorProfile xColors) { MainUI = mainUI; XColors = xColors; NodeModels = new NodeModel[XRay.Nodes.Length]; foreach (var node in XRay.Nodes) { NodeModels[node.ID] = new NodeModel(this, XRay.Nodes[node.ID]); } foreach (var uiNode in NodeModels) { if (uiNode.XNode.Parent != null) { uiNode.Parent = NodeModels[uiNode.XNode.Parent.ID]; } foreach (var subnode in uiNode.XNode.Nodes) { uiNode.Nodes.Add(NodeModels[subnode.ID]); } } TopRoot = NodeModels[XRay.RootNode.ID]; InternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.Internal); ExternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.External); CurrentRoot = InternalRoot; }
/// <summary> /// Release all resources of Img /// </summary> public void Dispose() { this.IsDone = false; this.Error = null; this.PageCount = 0; this.Exif = null; this.ColorProfile = null; if (this.Image != null) { this.Image.Dispose(); } }
/// <summary> /// Load the image /// </summary> /// <param name="size">A custom size of image</param> /// <param name="colorProfileName">Name or Full path of color profile</param> /// <param name="isApplyColorProfileForAll">If FALSE, only the images with embedded profile will be applied</param> /// <param name="channel">MagickImage.Channel value</param> /// <param name="useEmbeddedThumbnail">Use the embeded thumbnail if found</param> public async Task LoadAsync(Size size = new Size(), string colorProfileName = "", bool isApplyColorProfileForAll = false, int channel = -1, bool useEmbeddedThumbnail = false) { // reset done status this.IsDone = false; // reset error this.Error = null; try { // load image data var data = await Photo.LoadAsync( filename : this.Filename, size : size, colorProfileName : colorProfileName, isApplyColorProfileForAll : isApplyColorProfileForAll, channel : channel, useEmbeddedThumbnail : useEmbeddedThumbnail ); this.Image = data.Image; this.Exif = data.Exif; this.ColorProfile = data.ColorProfile; if (this.Image != null) { // Get page count var dim = new FrameDimension(this.Image.FrameDimensionsList[0]); this.PageCount = this.Image.GetFrameCount(dim); } } catch (Exception ex) { // save the error this.Error = ex; } // done loading this.IsDone = true; }
/// <summary> /// Load image from file /// </summary> /// <param name="filename">Full path of image file</param> /// <param name="size">A custom size of image</param> /// <param name="colorProfileName">Name or Full path of color profile</param> /// <param name="isApplyColorProfileForAll">If FALSE, only the images with embedded profile will be applied</param> /// <param name="quality">Image quality</param> /// <param name="channel">MagickImage.Channel value</param> /// <param name="useEmbeddedThumbnail">Return the embedded thumbnail if required size was not found.</param> /// <param name="useRawThumbnail">Return the RAW embedded thumbnail if found.</param> /// <param name="forceLoadFirstPage">Only load first page of the image</param> /// <returns>Bitmap</returns> public static ImgData Load( string filename, Size size = new Size(), string colorProfileName = "sRGB", bool isApplyColorProfileForAll = false, int quality = 100, int channel = -1, bool useEmbeddedThumbnail = false, bool useRawThumbnail = true, bool forceLoadFirstPage = false ) { Bitmap bitmap = null; IExifProfile exif = null; IColorProfile colorProfile = null; var ext = Path.GetExtension(filename).ToUpperInvariant(); var settings = new MagickReadSettings(); #region Settings if (ext == ".SVG") { settings.BackgroundColor = MagickColors.Transparent; settings.SetDefine("svg:xml-parse-huge", "true"); } if (size.Width > 0 && size.Height > 0) { settings.Width = size.Width; settings.Height = size.Height; } // Fixed #708: length and filesize do not match settings.SetDefines(new BmpReadDefines { IgnoreFileSize = true, }); // Fix RAW color settings.SetDefines(new DngReadDefines() { UseCameraWhitebalance = true, OutputColor = DngOutputColor.AdobeRGB, ReadThumbnail = true, }); #endregion #region Read image data switch (ext) { case ".TXT": // base64 string case ".B64": var base64Content = string.Empty; using (var fs = new StreamReader(filename)) { base64Content = fs.ReadToEnd(); } bitmap = ConvertBase64ToBitmap(base64Content); break; case ".GIF": case ".FAX": // Note: Using FileStream is much faster than using MagickImageCollection try { bitmap = ConvertFileToBitmap(filename); } catch { // #637: falls over with certain images, fallback to MagickImage ReadWithMagickImage(); } break; default: ReadWithMagickImage(); break; } #endregion #region Internal Functions // Preprocess magick image (IExifProfile, IColorProfile) PreprocesMagickImage(MagickImage imgM, bool checkRotation = true) { imgM.Quality = quality; IColorProfile imgColorProfile = null; IExifProfile profile = null; try { // get the color profile of image imgColorProfile = imgM.GetColorProfile(); // Get Exif information profile = imgM.GetExifProfile(); } catch { } // Use embedded thumbnails if specified if (profile != null && useEmbeddedThumbnail) { // Fetch the embedded thumbnail using var thumbM = profile.CreateThumbnail(); if (thumbM != null) { bitmap = thumbM.ToBitmap(); } } // Revert to source image if an embedded thumbnail with required size was not found. if (bitmap == null) { if (profile != null && checkRotation) { // Get Orientation Flag var exifRotationTag = profile.GetValue(ExifTag.Orientation); if (exifRotationTag != null) { if (int.TryParse(exifRotationTag.Value.ToString(), out var orientationFlag)) { var orientationDegree = Helpers.GetOrientationDegree(orientationFlag); if (orientationDegree != 0) { //Rotate image accordingly imgM.Rotate(orientationDegree); } } } } // if always apply color profile // or only apply color profile if there is an embedded profile if (isApplyColorProfileForAll || imgColorProfile != null) { var imgColor = Helpers.GetColorProfile(colorProfileName); if (imgColor != null) { imgM.TransformColorSpace( //set default color profile to sRGB imgColorProfile ?? ColorProfile.SRGB, imgColor); } } } return(profile, imgColorProfile); } void ReadWithMagickImage() { var checkRotation = ext != ".HEIC"; using var imgColl = new MagickImageCollection(); // Issue #530: ImageMagick falls over if the file path is longer than the (old) windows limit of 260 characters. Workaround is to read the file bytes, but that requires using the "long path name" prefix to succeed. if (filename.Length > 260) { var newFilename = Helpers.PrefixLongPath(filename); var allBytes = File.ReadAllBytes(newFilename); imgColl.Ping(allBytes, settings); } else { imgColl.Ping(filename, settings); } if (imgColl.Count > 1 && forceLoadFirstPage is false) { imgColl.Read(filename, settings); foreach (var imgPageM in imgColl) { (exif, colorProfile) = PreprocesMagickImage((MagickImage)imgPageM, checkRotation); } bitmap = imgColl.ToBitmap(); return; } using var imgM = new MagickImage(); if (useRawThumbnail is true) { var profile = imgColl[0].GetProfile("dng:thumbnail"); try { // try to get thumbnail imgM.Read(profile?.GetData(), settings); } catch { imgM.Read(filename, settings); } } else { imgM.Read(filename, settings); } // Issue #679: fix targa display with Magick.NET 7.15.x if (ext == ".TGA") { imgM.AutoOrient(); } imgM.Quality = quality; (exif, colorProfile) = PreprocesMagickImage(imgM, checkRotation); using var channelImgM = ApplyColorChannel(imgM, channel); bitmap = channelImgM.ToBitmap(); } #endregion return(new ImgData() { Image = bitmap, Exif = exif, ColorProfile = colorProfile, }); }
public ViewModel(IMainUI mainUI, IColorProfile xColors) { MainUI = mainUI; XColors = xColors; NodeModels = new NodeModel[XRay.Nodes.Length]; foreach (var node in XRay.Nodes) NodeModels[node.ID] = new NodeModel(this, XRay.Nodes[node.ID]); foreach (var uiNode in NodeModels) { if(uiNode.XNode.Parent != null) uiNode.Parent = NodeModels[uiNode.XNode.Parent.ID]; foreach (var subnode in uiNode.XNode.Nodes) uiNode.Nodes.Add(NodeModels[subnode.ID]); } TopRoot = NodeModels[XRay.RootNode.ID]; InternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.Internal); ExternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.External); CurrentRoot = InternalRoot; }
/// <summary> /// Load image from file /// </summary> /// <param name="filename">Full path of image file</param> /// <param name="size">A custom size of image</param> /// <param name="colorProfileName">Name or Full path of color profile</param> /// <param name="isApplyColorProfileForAll">If FALSE, only the images with embedded profile will be applied</param> /// <param name="quality">Image quality</param> /// <param name="channel">MagickImage.Channel value</param> /// <param name="useEmbeddedThumbnails">Return the embedded thumbnail if required size was not found.</param> /// <returns>Bitmap</returns> public static ImgData Load( string filename, Size size = new Size(), string colorProfileName = "sRGB", bool isApplyColorProfileForAll = false, int quality = 100, int channel = -1, bool useEmbeddedThumbnails = false ) { Bitmap bitmap = null; IExifProfile exif = null; IColorProfile colorProfile = null; var ext = Path.GetExtension(filename).ToUpperInvariant(); var settings = new MagickReadSettings(); #region Settings if (ext == ".SVG") { settings.BackgroundColor = MagickColors.Transparent; } if (size.Width > 0 && size.Height > 0) { settings.Width = size.Width; settings.Height = size.Height; } #endregion #region Read image data switch (ext) { case ".TXT": // base64 string case ".B64": var base64Content = string.Empty; using (var fs = new StreamReader(filename)) { base64Content = fs.ReadToEnd(); fs.Close(); } bitmap = ConvertBase64ToBitmap(base64Content); break; case ".GIF": case ".TIF": // Note: Using FileStream is much faster than using MagickImageCollection try { bitmap = ConvertFileToBitmap(filename); } catch { // #637: falls over with certain images, fallback to MagickImage ReadWithMagickImage(); } break; case ".ICO": case ".WEBP": using (var imgColl = new MagickImageCollection(filename, settings)) { bitmap = imgColl.ToBitmap(); } break; default: ReadWithMagickImage(); break; } #endregion #region Internal Functions // Preprocess magick image (IExifProfile, IColorProfile) PreprocesMagickImage(MagickImage imgM, bool checkRotation = true) { imgM.Quality = quality; IColorProfile imgColorProfile = null; IExifProfile profile = null; try { // get the color profile of image imgColorProfile = imgM.GetColorProfile(); // Get Exif information profile = imgM.GetExifProfile(); } catch { } // Use embedded thumbnails if specified if (profile != null && useEmbeddedThumbnails) { // Fetch the embedded thumbnail var thumbM = profile.CreateThumbnail(); if (thumbM != null) { bitmap = thumbM.ToBitmap(); } } // Revert to source image if an embedded thumbnail with required size was not found. if (bitmap == null) { if (profile != null && checkRotation) { // Get Orientation Flag var exifRotationTag = profile.GetValue(ExifTag.Orientation); if (exifRotationTag != null) { if (int.TryParse(exifRotationTag.Value.ToString(), out var orientationFlag)) { var orientationDegree = Helpers.GetOrientationDegree(orientationFlag); if (orientationDegree != 0) { //Rotate image accordingly imgM.Rotate(orientationDegree); } } } } // if always apply color profile // or only apply color profile if there is an embedded profile if (isApplyColorProfileForAll || imgColorProfile != null) { if (imgColorProfile != null) { // correct the image color space imgM.ColorSpace = imgColorProfile.ColorSpace; } else { // set default color profile and color space imgM.SetProfile(ColorProfile.SRGB); imgM.ColorSpace = ColorProfile.SRGB.ColorSpace; } var imgColor = Helpers.GetColorProfile(colorProfileName); if (imgColor != null) { imgM.SetProfile(imgColor); imgM.ColorSpace = imgColor.ColorSpace; } } } return(profile, imgColorProfile); } // Separate color channel MagickImage ApplyColorChannel(MagickImage imgM) { if (channel != -1) { var magickChannel = (Channels)channel; var channelImgM = (MagickImage)imgM.Separate(magickChannel).First(); if (imgM.HasAlpha && magickChannel != Channels.Alpha) { using (var alpha = imgM.Separate(Channels.Alpha).First()) { channelImgM.Composite(alpha, CompositeOperator.CopyAlpha); } } return(channelImgM); } return(imgM); } void ReadWithMagickImage() { MagickImage imgM; // Issue #530: ImageMagick falls over if the file path is longer than the (old) windows limit of 260 characters. Workaround is to read the file bytes, but that requires using the "long path name" prefix to succeed. if (filename.Length > 260) { var newFilename = Helpers.PrefixLongPath(filename); var allBytes = File.ReadAllBytes(newFilename); imgM = new MagickImage(allBytes, settings); } else { imgM = new MagickImage(filename, settings); } // Issue #679: fix targa display with Magick.NET 7.15.x if (ext == ".TGA") { imgM.AutoOrient(); } var checkRotation = ext != ".HEIC"; (exif, colorProfile) = PreprocesMagickImage(imgM, checkRotation); using (var channelImgM = ApplyColorChannel(imgM)) { bitmap = channelImgM.ToBitmap(); } imgM.Dispose(); } #endregion return(new ImgData() { Image = bitmap, Exif = exif, ColorProfile = colorProfile, }); }