/// <summary> /// Saves the project item as image to the provided stream. /// </summary> /// <param name="item">The item to export, for instance an item of type <see cref="Altaxo.Graph.Gdi.GraphDocument"/> or <see cref="Altaxo.Graph.Graph3D.GraphDocument"/>.</param> /// <param name="options">The export options.</param> /// <param name="toStream">The stream to save the image to.</param> public void ExportAsImageToStream(Altaxo.Main.IProjectItem item, Altaxo.Graph.Gdi.GraphExportOptions options, System.IO.Stream toStream) { if (item == null) throw new ArgumentNullException(nameof(item)); if (!(item is Altaxo.Graph.Graph3D.GraphDocument)) throw new ArgumentException(string.Format("Expected item of type {0}, but it is of type {1}", typeof(Altaxo.Graph.Graph3D.GraphDocument), item.GetType())); var doc = (Altaxo.Graph.Graph3D.GraphDocument)item; double sourceDpi = options.SourceDpiResolution; var exporter = new D3D10BitmapExporter(); var scene = new Viewing.D3D10Scene(); var g = new D3D10GraphicsContext(); doc.Paint(g); var matrix = doc.Camera.LookAtRHMatrix; var rect = new RectangleD3D(PointD3D.Empty, doc.RootLayer.Size); var bounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => matrix.Transform(x))); int pixelsX = (int)Math.Ceiling(sourceDpi * bounds.SizeX / 72.0); pixelsX = (int)(4 * Math.Ceiling((pixelsX + 3) / 4.0)); int pixelsY = (int)(sourceDpi * bounds.SizeY / 72.0); double aspectRatio = pixelsY / (double)pixelsX; var sceneCamera = doc.Camera; if (sceneCamera is OrthographicCamera) { var orthoCamera = (OrthographicCamera)sceneCamera; orthoCamera = (OrthographicCamera)orthoCamera.WithWidthAtZNear(bounds.SizeX); double offsX = -(1 + 2 * bounds.X / bounds.SizeX); double offsY = -(1 + 2 * bounds.Y / bounds.SizeY); sceneCamera = orthoCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else if (sceneCamera is PerspectiveCamera) { var viewProj = sceneCamera.GetViewProjectionMatrix(1); // here we transform the points with AspectRatio=1, in order to get the AspectRatio of the ScreenBounds var screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); aspectRatio = screenBounds.SizeY / screenBounds.SizeX; // this is the aspectRatio of our image viewProj = sceneCamera.GetViewProjectionMatrix(aspectRatio); // now we get the transform with our aspectRatio determined above screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); // this are our actual screenBounds, of course in relative screen coordinates, thus the ratio of sizeX and sizeY should now be 1 double scaleFactor = 2 / screenBounds.SizeX; // since SizeX and SizeY should now be the same, we could have used SizeY alternatively double offsX = -(1 + scaleFactor * screenBounds.X); double offsY = -(1 + scaleFactor * screenBounds.Y); pixelsY = (int)(4 * Math.Ceiling((aspectRatio * pixelsX + 3) / 4.0)); // now calculate the size of the image in y direction from the aspectRatio var perspCamera = (PerspectiveCamera)sceneCamera; sceneCamera = perspCamera.WithWidthAtZNear(perspCamera.WidthAtZNear / scaleFactor); sceneCamera = sceneCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else { throw new NotImplementedException(); } scene.SetCamera(sceneCamera); scene.SetLighting(doc.Lighting); scene.SetDrawing(g); exporter.Export(pixelsX, pixelsY, scene, options, toStream); }
/// <summary> /// Saves the project item as image to the provided stream. /// </summary> /// <param name="item">The item to export, for instance an item of type <see cref="Altaxo.Graph.Gdi.GraphDocument"/> or <see cref="Altaxo.Graph.Graph3D.GraphDocument"/>.</param> /// <param name="options">The export options.</param> /// <param name="toStream">The stream to save the image to.</param> public (int PixelsX, int PixelsY) ExportAsImageToStream(Altaxo.Main.IProjectItem item, Altaxo.Graph.Gdi.GraphExportOptions options, System.IO.Stream toStream) { // SharpDX.Configuration.EnableObjectTracking = true; // var listOfActiveObjects = SharpDX.Diagnostics.ObjectTracker.FindActiveObjects(); if (item == null) { throw new ArgumentNullException(nameof(item)); } if (!(item is Altaxo.Graph.Graph3D.GraphDocument)) { throw new ArgumentException(string.Format("Expected item of type {0}, but it is of type {1}", typeof(Altaxo.Graph.Graph3D.GraphDocument), item.GetType())); } var doc = (Altaxo.Graph.Graph3D.GraphDocument)item; double sourceDpi = options.SourceDpiResolution; Viewing.D3D10Scene scene = null; D3D10GraphicsContext g = null; try { scene = new Viewing.D3D10Scene(); g = new D3D10GraphicsContext(); doc.Paint(g); var matrix = doc.Camera.LookAtRHMatrix; var rect = new RectangleD3D(PointD3D.Empty, doc.RootLayer.Size); var bounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => matrix.Transform(x))); int pixelsX = (int)Math.Ceiling(sourceDpi * bounds.SizeX / 72.0); pixelsX = (int)(4 * Math.Ceiling((pixelsX + 3) / 4.0)); int pixelsY = (int)(sourceDpi * bounds.SizeY / 72.0); double aspectRatio = pixelsY / (double)pixelsX; var sceneCamera = doc.Camera; if (sceneCamera is OrthographicCamera) { var orthoCamera = (OrthographicCamera)sceneCamera; orthoCamera = (OrthographicCamera)orthoCamera.WithWidthAtZNear(bounds.SizeX); double offsX = -(1 + 2 * bounds.X / bounds.SizeX); double offsY = -(1 + 2 * bounds.Y / bounds.SizeY); sceneCamera = orthoCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else if (sceneCamera is PerspectiveCamera) { var viewProj = sceneCamera.GetViewProjectionMatrix(1); // here we transform the points with AspectRatio=1, in order to get the AspectRatio of the ScreenBounds var screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); aspectRatio = screenBounds.SizeY / screenBounds.SizeX; // this is the aspectRatio of our image viewProj = sceneCamera.GetViewProjectionMatrix(aspectRatio); // now we get the transform with our aspectRatio determined above screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); // this are our actual screenBounds, of course in relative screen coordinates, thus the ratio of sizeX and sizeY should now be 1 double scaleFactor = 2 / screenBounds.SizeX; // since SizeX and SizeY should now be the same, we could have used SizeY alternatively double offsX = -(1 + scaleFactor * screenBounds.X); double offsY = -(1 + scaleFactor * screenBounds.Y); pixelsY = (int)(4 * Math.Ceiling((aspectRatio * pixelsX + 3) / 4.0)); // now calculate the size of the image in y direction from the aspectRatio var perspCamera = (PerspectiveCamera)sceneCamera; sceneCamera = perspCamera.WithWidthAtZNear(perspCamera.WidthAtZNear / scaleFactor); sceneCamera = sceneCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else { throw new NotImplementedException(); } scene.SetCamera(sceneCamera); scene.SetLighting(doc.Lighting); scene.SetDrawing(g); Export(pixelsX, pixelsY, scene, options, toStream); return(pixelsX, pixelsY); } finally { Disposer.RemoveAndDispose(ref g); Disposer.RemoveAndDispose(ref scene); } }