I wonder if there is any way to give a name to a writeableBitmap
I have 3 images in my folder. To display them in a gridView I convert them to a wrtieableBitmap
if (file.Count > 0)
{
var images = new List<WriteableBitmap>();
foreach (StorageFile f in file)
{
var name = f.Name;
Debug.WriteLine(f.Name);
ImageProperties properties = await f.Properties.GetImagePropertiesAsync();
if (properties.Width > 0)
{
var bitmap = new WriteableBitmap((int)properties.Width, (int)properties.Height);
Debug.WriteLine(bitmap.PixelWidth);
using (var stream = await f.OpenAsync(FileAccessMode.ReadWrite))
{
bitmap.SetSource(stream);
}
images.Add(bitmap);
Debug.WriteLine(images.Count);
}
}
The I add them to the gridView by binding the Data as in AlGridView.DataContext = images;
Now, once I interact with those images and I press a button I need to save the selection...but using an array with numbers [1,2,3]
Before converting them, as you may see above, I had a name (which is 1.png, 2.png, etc) but once they are writeablebitmaps I havenĀ“t found any way to give / get a name out of them
And
bitmap.SetVale(Name, f.Name);
Does not work, since it says it cannot convert a string into a DependencyProperty
Any ideas?
Ha!. I think I have found the solution:
properties.Title = name;
var bitmap = new WriteableBitmap((int)properties.Width, (int)properties.Height);
bitmap.SetValue(NameProperty, (string)properties.Title);
Thank you all!
Related
I am currently using the OxyPlot and QuestPDF libraries to be able to generate a PDF with charts. I have designed a pie chart and a bar chart. I am currently saving the charts, exporting them to SVG, inside a folder, and then adding them to the PDF. I would like to change this and save them in memory and then yes, add them to the PDF.
According to the documentation I read from the OxyPlot library, it has an option to save the plot to a PNG in memory, but then I don't know how to insert it into the PDF:
var stream = new MemoryStream();
var pngExporter = new PngExporter { Width = 600, Height = 400, Background = OxyColors.White };
pngExporter.Export(plotModel, stream);
I leave below the code that I am using to export the graph, in SVG format, and saving it in a folder. And then, I add it to the PDF. This is how I generate the SVG and export it:
using (var stremPieChart = File.Create("pieChart.svg"))
{
var exporter = new OxyPlot.SvgExporter { Width = 400, Height = 300, UseVerticalTextAlignmentWorkaround = true };
exporter.Export(newPieModel, stremPieChart);
}
And so I add it to the PDF:
.Element(element =>
{
element
.PaddingTop(-13)
.PaddingLeft(4)
.AlignCenter()
.Canvas((canvas, size) =>
{
var pieChartSvg = new SKSvg();
pieChartSvg.Load("pieChart.svg");
canvas.Scale(0.65f);
canvas.DrawPicture(pieChartSvg.Picture);
});
});
I hope you can help me! Thank you!
Unfortunately I couldn't save the svg in memory because the library doesn't allow in-memory export. So, I had to modify the logic to be able to save the svg to a temporary file and then consume and delete it. This is how I got the code:
.Element(element =>
{
element
.PaddingTop(-13)
.PaddingLeft(4)
.AlignCenter()
.Canvas((canvas, size) =>
{
string pieChartTemp = Path.GetTempFileName();
using (var stremPieChart = File.Create(pieChartTemp))
{
var exporter = new OxyPlot.SvgExporter
{
Width = 400,
Height = 300,
UseVerticalTextAlignmentWorkaround = true
};
exporter.Export(newPieModel, stremPieChart);
}
var pieChartSvg = new SKSvg();
pieChartSvg.Load(pieChartTemp);
canvas.Scale(0.65f);
canvas.DrawPicture(pieChartSvg.Picture);
File.Delete(pieChartTemp);
});
});
As you can see, I first created a temporary path and then generated the .svg on that path.
Then to load the SVG, I insert the temporary path.
Since SVG is just text, you can probably save it in MemoryStream instead of FileStream, export it to array of bytes and then using encoding.GetString() to get the resulting text content of svg.
If this works, when loading your image you can pieChartSvg.FromSvg(svg) it.
like so:
string svgString;
using (var stremPieChart = new MemoryStream())
{
var exporter = new OxyPlot.SvgExporter {
Width = 400,
Height = 300,
UseVerticalTextAlignmentWorkaround = true
};
exporter.Export(newPieModel, stremPieChart);
/// UTF8 or whatever the encoding may be, anyways...
svgString = System.Text.Encoding.UTF8.GetString(stremPieChart)
}
and later
.Element(element =>
{
element
.PaddingTop(-13)
.PaddingLeft(4)
.AlignCenter()
.Canvas((canvas, size) =>
{
var pieChartSvg = new SKSvg();
pieChartSvg.FromSvg(svgString);
canvas.Scale(0.65f);
canvas.DrawPicture(pieChartSvg.Picture);
});
});
Update
According to OxyPlot's github repository, even though not documented, SvgExporter seem to have a method named ExportToString which works better with my example and doesn't create problems about the stream type.
relevant code: here (line 115 - 123)
That said, my example could be like:
string svgString;
using (var stremPieChart = new MemoryStream())
{
var exporter = new OxyPlot.SvgExporter {
Width = 400,
Height = 300,
UseVerticalTextAlignmentWorkaround = true
};
// CHANGE HERE!
svgString = exporter.ExportToString(newPieModel);
}
and later
.Element(element =>
{
element
.PaddingTop(-13)
.PaddingLeft(4)
.AlignCenter()
.Canvas((canvas, size) =>
{
var pieChartSvg = new SKSvg();
pieChartSvg.FromSvg(svgString);
canvas.Scale(0.65f);
canvas.DrawPicture(pieChartSvg.Picture);
});
});
In the below For loop, after the loop has finished, it increments the counter one last time e.g. if the condition is i<2, it will increment to 2 before exiting the loop. The images list will then try to use the value images[2] which doesn't exist. This will result in images not displaying
I know there are other questions on using an anonymous method within a loop and I've applied the recommended solutions, but no such luck.
This is my code behind
FileModel fileModel = DependencyService.Get<IImageFetcher>().ReadImagesAsync();
var items = new List<FileImageInfo>();
for (int i = 0; i < fileModel.Images.Count; i++)
{
var imageStream = ImageSource.FromStream(() => new MemoryStream(fileModel.Images[i]));
items.Add(new FileImageInfo
{
FileType = "Jpeg",
FileSize = fileModel.Sizes[i],
DateCreated = fileModel.Dates[i],
imageSource = imageStream
});
}
Items.ItemsSource = items;
the above code works indicating the issue is definitely with the loop and not with the images or anything else
Using a foreach loop did the trick. Was told over on the Xamarin forum that have to use foreach not For with listview images
I have worked a bit with OpenXML SDK, and made a POC of replacing images in a header in a word document. However, when I try to call DeletePart or DeleteParts with the images I want to remove, it doesn't go as expected.
When I open the word doc afterwards, where there before was an image, there now is a frame with the text "This image cannot currently be displayed" and a red cross.
From a bit of googling it appears as if the references have not been completely removed, but I can't find any help on how to do that..
Below is an example of how I delete images. I only add some of them to the list, because I need to remove all but the ones with a specific uri..
//...
foreach(HeaderPart headerPart in document.MainDocumentPart.HeaderParts) {
List<ImagePart> list = new List<ImagePart>();
List<ImagePart> imgParts = new List<ImagePart> (headerPart.ImageParts);
foreach(ImagePart headerImagePart in imgParts) {
string newUri = headerImagePart.Uri.ToString();
if(newUri != uri) {
list.Add(headerImagePart);
}
}
headerPart.DeleteParts(list);
}
//...
Images are made up of 2 parts in OpenXml; you have the actual image itself and you also have details of the Picture container that the image is displayed within in the document.
This makes sense if you think about an image being displayed more than once in the same document; details of the image can be stored once and the position(s) of the image can be stored as many times as needed.
The following code will find any Drawing objects that contain the ImagePart objects that you wish to delete. This is done by matching the Embed property of the Blip against the Id of the ImagePart.
using (WordprocessingDocument document = WordprocessingDocument.Open(filename, true))
{
foreach (HeaderPart headerPart in document.MainDocumentPart.HeaderParts)
{
List<ImagePart> list = new List<ImagePart>();
List<ImagePart> imgParts = new List<ImagePart>(headerPart.ImageParts);
List<Drawing> drwdDeleteParts = new List<Drawing>();
List<Drawing> drwParts = new List<Drawing>(headerPart.RootElement.Descendants<Drawing>());
foreach (ImagePart headerImagePart in imgParts)
{
string newUri = headerImagePart.Uri.ToString();
if (newUri != uri)
{
list.Add(headerImagePart);
//you also need to find the Drawings the image was related to
IEnumerable<Drawing> drawings = drwParts.Where(d => d.Descendants<Pic.Picture>().Any(p => p.BlipFill.Blip.Embed == headerPart.GetIdOfPart(headerImagePart)));
foreach (var drawing in drawings)
{
if (drawing != null && !drwdDeleteParts.Contains(drawing))
drwdDeleteParts.Add(drawing);
}
}
}
foreach (var d in drwdDeleteParts)
{
d.Remove();
}
headerPart.DeleteParts(list);
}
}
As you pointed out in the comments, you'll need to add a using statement:
Pic = DocumentFormat.OpenXml.Drawing.Pictures;
I'm trying to save my list of images to a folder determined by the user, in this case I have this list.
List<System.Drawing.Image> ListOfSystemDrawingImage = new List<System.Drawing.Image>();
ListOfSystemDrawingImage.Add(MatrizWPF.Properties.Resources.Earth);
ListOfSystemDrawingImage.Add(MatrizWPF.Properties.Resources.Grass);
ListOfSystemDrawingImage.Add(MatrizWPF.Properties.Resources.Rabbit);
ListOfSystemDrawingImage.Add(MatrizWPF.Properties.Resources.Wolf);
Where Earth, Grass, Rabbit and Wolf are PNG images called the same way.
My question is, How can I store my
List<System.Drawing.Image> listOfSystemDrawingImage = new List<System.Drawing.Image>();
To a folder determined by the user?
You can use System.Windows.Forms.FolderBrowserDialog for the user to pick the destination folder and use the Image.Save to save the image in the format of your chioce
Example:
List<System.Drawing.Image> listOfSystemDrawingImage = new List<System.Drawing.Image>();
System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
int index = 0;
foreach (var image in listOfSystemDrawingImage)
{
image.Save(string.Format("{0}\\Image{1}.png", dialog.SelectedPath, index), System.Drawing.Imaging.ImageFormat.Png);
index++;
}
}
However, I do not recommend mixing Window.Forms and System.Drawing with WPF,
If you have the names you can just convert the image to a byte array and then use File.WriteAllBytes. Make sure the file name you pass toe WriteAllBytes has a .png extension. There's probably a simpler way but I don't really deal with media like that as much as raw data so this is what comes to mind for me.
You can save the list of System.Drawing.Image this way:
string folder = #"C:\temp";
int count = 1;
foreach(Image image in listOfSystemDrawingImage)
{
string path = Path.Combine(folder, String.Format("image{0}.png", count));
image.Save(path);
count++;
}
I don't know where you store the image names, so I just called them image1.png, image2.png, and so on.
Hi I need bind images to listbox but when I try it I get FILE NOT FOUND but file is stored in application package in folder layoutGraphics. I try put files to default folder but I get same result anyone know what is bad?
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync("ms-appx:///layoutGraphics/offline.png");
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var img = new BitmapImage();
img.SetSource(fileStream);
ImgSource = img;
// property
private BitmapImage _imgSource;
public BitmapImage ImgSource
{
get { return _imgSource; }
set
{
_imgSource = value;
OnPropertyChanged("MyDatasMessagesUserList");
}
}
Or anyone know better solution how I can bind imagess from app folder to my listbox with datatemplate?
Windows.Storage.ApplicationData.Current.LocalFolder is retriving file from the application storage not the package. For the package folder you need to use Windows.ApplicationModel.Package.Current.InstalledLocation. Also the GetFileAsync take just the name of a file not a full path.
Here is the code to acomplish what you want:
var layoutGraphiceFolder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("layoutGraphics")
var file=await layoutGraphiceFolder.GetFileAsync("offline.png");
Another way to do it with the full path is:
var file=await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///layoutGraphics/offline.png"));