public ExportDialog(Models.Models models, string filename, ImageLoader.ImageFormat defaultPixelFormat, ExportModel.FileFormat format) { models.Export.Init(filename, defaultPixelFormat, format); viewModel = new ExportViewModel(models); DataContext = viewModel; InitializeComponent(); }
// initializes the export model for a new export public void Init(string filename, ImageLoader.ImageFormat pixelFormat, FileFormat fileFormat) { Filename = filename; FileType = fileFormat; HasQuality = false; var supportedFormats = new List <DisplayedFormat>(); switch (fileFormat) { case FileFormat.Png: supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Red, PixelType.UnsignedByte, true), "Red")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Green, PixelType.UnsignedByte, true), "Green")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Blue, PixelType.UnsignedByte, true), "Blue")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Alpha, PixelType.UnsignedByte, true), "Alpha")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rg, PixelType.UnsignedByte, true), "RG")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.UnsignedByte, true), "RGB")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rgba, PixelType.UnsignedByte, true), "RGBA")); break; case FileFormat.Dds: case FileFormat.Ktx: for (int i = (int)GliFormat.FORMAT_FIRST; i <= (int)GliFormat.LAST; ++i) { var format = (GliFormat)i; if (!Gli.IsSupported(format)) { continue; } var imgf = new ImageLoader.ImageFormat(format); // TODO support compressed format as well if (!imgf.IsCompressed) { supportedFormats.Add(new DisplayedFormat(imgf, format.ToString())); } } break; case FileFormat.Ktx2: // TODO: Implement. break; case FileFormat.Jpg: supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Red, PixelType.UnsignedByte, true), "Red")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Green, PixelType.UnsignedByte, true), "Green")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Blue, PixelType.UnsignedByte, true), "Blue")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Alpha, PixelType.UnsignedByte, true), "Alpha")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.UnsignedByte, true), "RGB")); HasQuality = true; MinQuality = 1; MaxQuality = 100; Quality = Properties.Settings.Default.JpgQuality; break; case FileFormat.Bmp: supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Red, PixelType.UnsignedByte, true), "Red")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Green, PixelType.UnsignedByte, true), "Green")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Blue, PixelType.UnsignedByte, true), "Blue")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Alpha, PixelType.UnsignedByte, true), "Alpha")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rg, PixelType.UnsignedByte, true), "RG")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.UnsignedByte, true), "RGB")); break; case FileFormat.Hdr: case FileFormat.Pfm: supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Red, PixelType.Float, false), "Red")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Green, PixelType.Float, false), "Green")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Blue, PixelType.Float, false), "Blue")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Alpha, PixelType.Float, false), "Alpha")); supportedFormats.Add(new DisplayedFormat(new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.Float, false), "RGB")); break; } // select preferred texture format TexFormat = supportedFormats.Last(); foreach (var df in supportedFormats) { if (df.Format.Equals(pixelFormat)) { TexFormat = df; } } SupportedFormats = supportedFormats; Layer = displayModel.ActiveLayer; Mipmap = displayModel.ActiveMipmap; }
public DisplayedFormat(ImageLoader.ImageFormat format, string displayedName) { Format = format; DisplayedName = displayedName; }
public void Execute(object parameter) { if (models.Images.NumImages == 0) { return; } // make sure only one image is visible if (models.Equations.NumVisible != 1) { App.ShowInfoDialog(models.App.Window, "Exactly one image equation should be visible when exporting."); return; } // get active final image var equationId = models.Equations.GetFirstVisible(); var firstImageId = models.Equations.Get(equationId).ColorFormula.FirstImageId; var proposedFilename = firstImageId < models.Images.NumImages ? System.IO.Path.GetFileNameWithoutExtension(models.Images.GetFilename(firstImageId)) : ""; // open save file dialog var sfd = new SaveFileDialog { Filter = "PNG (*.png)|*.png|BMP (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg|HDR (*.hdr)|*.hdr|Portable float map (*.pfm)|*.pfm|Khronos Texture (*.ktx)|*.ktx|Khronos Texture (*.ktx2)|*.ktx2|DirectDraw Surface (*.dds)|*.dds", InitialDirectory = Properties.Settings.Default.ExportPath, FileName = proposedFilename }; if (sfd.ShowDialog() != true) { return; } Properties.Settings.Default.ExportPath = System.IO.Path.GetDirectoryName(sfd.FileName); // obtain file format var format = ExportModel.FileFormat.Png; if (sfd.FileName.EndsWith(".bmp")) { format = ExportModel.FileFormat.Bmp; } else if (sfd.FileName.EndsWith(".hdr")) { format = ExportModel.FileFormat.Hdr; } else if (sfd.FileName.EndsWith(".pfm")) { format = ExportModel.FileFormat.Pfm; } else if (sfd.FileName.EndsWith(".jpg")) { format = ExportModel.FileFormat.Jpg; } else if (sfd.FileName.EndsWith(".ktx")) { format = ExportModel.FileFormat.Ktx; } else if (sfd.FileName.EndsWith(".ktx2")) { format = ExportModel.FileFormat.Ktx2; } else if (sfd.FileName.EndsWith(".dds")) { format = ExportModel.FileFormat.Dds; } var texFormat = new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.UnsignedByte, true); switch (format) { case ExportModel.FileFormat.Png: case ExportModel.FileFormat.Bmp: case ExportModel.FileFormat.Jpg: if (models.Images.IsAlpha && format == ExportModel.FileFormat.Png) { texFormat.ExternalFormat = PixelFormat.Rgba; } if (models.Images.IsGrayscale) { texFormat.ExternalFormat = PixelFormat.Red; } break; case ExportModel.FileFormat.Hdr: case ExportModel.FileFormat.Pfm: texFormat = new ImageLoader.ImageFormat(PixelFormat.Rgb, PixelType.Float, false); if (models.Images.IsGrayscale) { texFormat.ExternalFormat = PixelFormat.Red; } break; case ExportModel.FileFormat.Ktx: case ExportModel.FileFormat.Ktx2: case ExportModel.FileFormat.Dds: // load default format from settings if (Enum.TryParse <GliFormat>(Properties.Settings.Default.GliFormat, out var fmt)) { texFormat = new ImageLoader.ImageFormat(fmt); } else { texFormat = new ImageLoader.ImageFormat(GliFormat.RGB8_SRGB_PACK8); } break; } models.Export.IsExporting = true; // open export dialog var dia = new ExportDialog(models, sfd.FileName, texFormat, format); dia.Owner = models.App.Window; dia.Closed += (sender, args) => { models.Export.IsExporting = false; // save gli format if present var fmt = models.Export.TexFormat.Format; if (fmt.HasGliFormat) { Properties.Settings.Default.GliFormat = fmt.GliFormat.ToString(); } if (!dia.ExportResult) { return; } var info = models.Export; models.GlContext.Enable(); try { // obtain data from gpu var texture = models.FinalImages.Get(equationId).Texture; if (texture == null) { throw new Exception("texture is not computed"); } if (info.FileType == ExportModel.FileFormat.Ktx || info.FileType == ExportModel.FileFormat.Ktx2 || info.FileType == ExportModel.FileFormat.Dds) { SaveMultipleLevel(info, texture); } else { SaveSingleLevel(info, texture); } } catch (Exception e) { App.ShowErrorDialog(models.App.Window, e.Message); } finally { models.GlContext.Disable(); } }; dia.Show(); }
/// <summary> /// reads (sub) data from a single image layer and a single image mipmap with the specified format and type /// </summary> /// <param name="layer">image layer</param> /// <param name="mipmap">image mipmap</param> /// <param name="format">destination format</param> /// <param name="type">destination type</param> /// <param name="toSrgb">indicates if data should be converted into srgb space</param> /// <param name="useCropping">indicates if the source image should be cropped</param> /// <param name="xOffset">if useCropping: x pixel offset</param> /// <param name="yOffset">if useCropping: y pixel offset</param> /// <param name="width">if useCropping: width of destination image. Will be set to the exported image width</param> /// <param name="height">if useCropping: height of destination image. Will be set to the exported image height</param> /// <param name="exportShader">shader required for srgb conversion and cropping</param> /// <param name="bufferSize"> Expected size of buffer in bytes. If bufferSize = 0 the buffer size will be calculated based the pixel type size times the number of pixel components (this only works for simple formats)</param> /// <returns></returns> public byte[] GetData(int layer, int mipmap, ImageLoader.ImageFormat format, bool useCropping, int xOffset, int yOffset, ref int width, ref int height, PixelExportShader exportShader, int bufferSize = 0) { Debug.Assert(!format.IsCompressed); // retrieve width and height of the mipmap GL.BindTexture(TextureTarget.Texture2DArray, id); GL.GetTexLevelParameter(TextureTarget.Texture2DArray, mipmap, GetTextureParameter.TextureWidth, out int maxWidth); GL.GetTexLevelParameter(TextureTarget.Texture2DArray, mipmap, GetTextureParameter.TextureHeight, out int maxHeight); Debug.Assert(layer < nLayer); Debug.Assert(mipmap < nMipmaps); if (useCropping) { Debug.Assert(xOffset + width <= maxWidth); Debug.Assert(yOffset + height <= maxHeight); } else { xOffset = 0; yOffset = 0; width = maxWidth; height = maxHeight; } int bs = bufferSize; // try to calculate the buffer size (only for simple formats) if (bs == 0) { bs = width * height * GetPixelTypeSize(format.Type) * GetPixelFormatCount(format.Format); } byte[] buffer = new byte[bs]; //if (format.IsSrgb || useCropping) // This needs to be used due to some export bug with certain formats (e.g. RGBA4_UNORM_PACK16) { // create temporary texture and convert data var tmpTex = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, tmpTex); GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba32f, width, height); // use crop/srgb shader GL.BindImageTexture(exportShader.GetDestinationTextureLocation(), tmpTex, 0, false, 0, TextureAccess.WriteOnly, SizedInternalFormat.Rgba32f); BindAsTexture2D(exportShader.GetSourceTextureLocation(), layer, mipmap); exportShader.Use(xOffset, yOffset, width, height, format.IsSrgb); // obtain data GL.BindTexture(TextureTarget.Texture2D, tmpTex); GL.GetTexImage(TextureTarget.Texture2D, 0, format.Format, format.Type, buffer); // cleanup GL.DeleteTexture(tmpTex); } //else //{ // // read directly (NOT POSSIBLE DUE TO EXPORT BUG e.g. RGBA4_UNORM_PACK16) // BindAsTexture2D(0, layer, mipmap); // GL.GetTexImage(TextureTarget.Texture2D, 0, format.Format, format.Type, buffer); //} return(buffer); }