How do I get an image to save after rotation at runtime? - c#

I am working with WPF and I have an application that the user loads an image file into a RichTextBox and they can rotate the image and print it. I am not sure as to why the image after it has been rotated will not print as it is displayed on the screen. Instead it prints the original. I am new to this so any help would be greatly appreciated!
The following is the code for my application. Code when the retrieve file Button is clicked:
private void retrieve_button_Click(object sender, RoutedEventArgs e)
{
//Retrieve the file or image you are looking for
OpenFileDialog of = new OpenFileDialog();
of.Filter = "Formats|*.jpg;*.png;*.bmp;*.gif;*.ico;*.txt|JPG Image|*.jpg|BMP image|*.bmp|PNG image|*.png|GIF Image|*.gif|Icon|*.ico|Text File|*.txt";
var dialogResult = of.ShowDialog();
if (dialogResult == System.Windows.Forms.DialogResult.OK)
{
try
{
System.Windows.Controls.RichTextBox myRTB = new System.Windows.Controls.RichTextBox();
{
Run myRun = new Run();
System.Windows.Controls.Image MyImage = new System.Windows.Controls.Image();
MyImage.Source = new BitmapImage(new Uri(of.FileName, UriKind.RelativeOrAbsolute));
InlineUIContainer MyUI = new InlineUIContainer();
MyUI.Child = MyImage;
rotateright_button.IsEnabled = true;
print_button.IsEnabled = true;
Paragraph paragraph = new Paragraph();
paragraph.Inlines.Add(myRun);
paragraph.Inlines.Add(MyUI);
FlowDocument document = new FlowDocument(paragraph);
richTextBox.Document = document;
}
}
catch (ArgumentException)
{
System.Windows.Forms.MessageBox.Show("Invalid File");
}
}
}
When the rotate right button is clicked the following code is executed:
RotateTransform cwRotateTransform;
private void rotateright_button_Click(object sender, RoutedEventArgs e)
{
richTextBox.LayoutTransform = cwRotateTransform;
if (cwRotateTransform == null)
{
cwRotateTransform = new RotateTransform();
}
if (cwRotateTransform.Angle == 360)
{
cwRotateTransform.Angle = 0;
}
else
{
cwRotateTransform.Angle += 90;
}
}
After the Image has been loaded and rotated the user can use the following code to print:
private void InvokePrint(object sender, RoutedEventArgs e)
{
System.Windows.Controls.PrintDialog printDialog = new System.Windows.Controls.PrintDialog();
if ((bool)printDialog.ShowDialog().GetValueOrDefault())
{
FlowDocument flowDocument = new FlowDocument();
flowDocument = richTextBox.Document;
flowDocument.ColumnWidth = printDialog.PrintableAreaWidth;
flowDocument.PagePadding = new Thickness(65);
IDocumentPaginatorSource iDocPag = flowDocument;
printDialog.PrintDocument(iDocPag.DocumentPaginator, "Print Document");
}
}

Try this (substitute yourImageControl in the first line, specify which RotateFlipType you want and be sure to reference the System.Drawing dll):
System.Drawing.Bitmap bitmap = BitmapSourceToBitmap((BitmapSource)YourImageControl.Source);
bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource bitmapsource)
{
System.Drawing.Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
return bitmap;
}
Another option for conversion...
P.S. You would get a better answer in less time if you posted some code and told us more about what you have tried.

Related

image doesn't change - WPF

I'm trying to change an image on runtime but it's not working.
I have a user control that when you click on imagebtn it's opening a new window with a list of images.
the next step is to take the image selected from the list, close the new window, and put the image on the imagebtn.
the user control still opens in the background.
this is my code.
NewWindow:
private string myData;
public ImagesWindow()
{
InitializeComponent();
InitialImageList();
}
private async void InitialImageList()
{
//add try catch
string get = await HttpRequests.GetRequest(URLImages);
allJsonCategory = JsonConvert.DeserializeObject<List<ImageArray>>(get);
Console.WriteLine(get);
ImageBoxList.ItemsSource = images;
foreach (var item in allJsonCategory)
{
images.Add(item);
}
}
private void ImageBoxList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
selectedImage = (ImageArray)ImageBoxList.SelectedItem;
myData = selectedImage.full_path;
Console.WriteLine("you clicked on: " + selectedImage.name);
ProductsCategory pro = new ProductsCategory();
pro.imagePath = myData;
this.Close();
}
my usercontrol(in mainWindow):
public void setImage(string imagePath)
{
if (!imageURL.Equals(""))
{
Image imageBtn = new Image();
var imgUrl = new Uri(imagePath);
var imageData = new WebClient().DownloadData(imgUrl);
// or you can download it Async won't block your UI
// var imageData = await new WebClient().DownloadDataTaskAsync(imgUrl);
var bitmapImage = new BitmapImage { CacheOption = BitmapCacheOption.OnLoad };
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageData);
bitmapImage.EndInit();
imageBtn.Source = bitmapImage;
//this.imageBtn.InvalidateVisual();
}
}
XAML of the image:
where is my mistake?
thank you all :)

Add Adorner to Image in WPF RichTextBox when loaded

I have a RichTextBox control in an application I am developing which I am using along with a ToolBar to create a rich text editor. One feature I have implemented is the ability for a user to insert an Image, now it worth noting at this point that the output from the RichTextBox is RTF.
When the user inserts the Image I am using the following code to add the image to the Document and then add a ResizeAdorner (example from here RichTextBox Resizing Adorner) to the Image which allows the user to resize. When the user saves and loads the Document the size of the Image is persisted correctly.
private void BtnInsertImage_OnClick(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = false;
ofd.CheckFileExists = true;
ofd.CheckPathExists = true;
ofd.Filter = "Image files (*.png;*.jpg;*.jpeg;*.gif;*.bmp)|*.png;*.jpg;*.jpeg;*.gif;*.bmp";
ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
ofd.Title = "Insert Image";
if (ofd.ShowDialog() == true)
{
BitmapImage bitmap = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute))
{
CacheOption = BitmapCacheOption.OnLoad
};
Image image = new Image();
image.IsEnabled = true;
image.Source = bitmap;
image.Width = bitmap.Width;
image.Height = bitmap.Height;
image.Loaded += this.ImageOnLoaded;
image.Stretch = Stretch.Uniform;
InlineUIContainer container = new InlineUIContainer(image, this.rtbEditor.Selection.Start);
Paragraph paragraph = new Paragraph(container);
var doc = this.rtbEditor.Document;
doc.Blocks.Add(paragraph);
}
}
private void ImageOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var img = sender as Image;
if (img != null)
{
var al = AdornerLayer.GetAdornerLayer(img);
if (al != null)
{
al.Add(new ResizingAdorner(img));
}
}
}
The problem and question is that when the Document is loaded i am unable to figure out how to add the ResizingAdorner to the Images in the document. I am using an attached property to load the document contents, the code below is the part that loads the document:
var stream = new MemoryStream(Encoding.UTF8.GetBytes(GetDocumentXaml(richTextBox)));
var doc = new FlowDocument();
var range = new TextRange(doc.ContentStart, doc.ContentEnd);
range.Load(stream, DataFormats.Xaml);
richTextBox.Document = doc;
Could anyone help with how I can add the ResizingAdorner to any images in the loaded Document please?
So I have worked out a way that I can add the Adorner to the Image in the Document through the SelectionChanged event handler and the following code
var inline = this.rtbEditor.CaretPosition.GetAdjacentElement(LogicalDirection.Forward) as Inline;
if (inline != null)
{
this.AddAdorner(inline.NextInline as InlineUIContainer);
this.AddAdorner(inline.PreviousInline as InlineUIContainer);
}
And this is the AddAdorner method
private void AddAdorner(InlineUIContainer container)
{
if (container != null)
{
var image = container.Child;
if (image != null)
{
var al = AdornerLayer.GetAdornerLayer(image);
if (al != null)
{
var currentAdorners = al.GetAdorners(image);
if (currentAdorners != null)
{
foreach (var adorner in currentAdorners)
{
al.Remove(adorner);
}
}
al.Add(new ResizingAdorner(image));
}
}
}
}
I know this is probably not the most elegant way to achieve this but for me this works so I wanted to post this so that others can choose to use this if appropriate

How to save only the image that is showing from my picturebox

I am trying to figure out how to save a snapshot of a video being shown from a picturebox control. I can already save an image file, however my problem is the whole image that is 'seen' by my camera is the one that is being saved. What I would like to save is the image that is only being shown from my picturebox control, which is just a portion of what the camera is capturing. By the way I am using Aforge framework set of video libraries.
My picturebox is set at Height = 400 and Width = 400.
Here is a sample of my code
private void Form1_Load(object sender, EventArgs e)
{
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in videoDevices)
{
drvrlist.Items.Add(device.Name);
}
drvrlist.SelectedIndex = 1;
videosource = new VideoCaptureDevice();
if (videosource.IsRunning)
{
videosource.Stop();
}
else
{
videosource = new VideoCaptureDevice(videoDevices[comboBox1.SelectedIndex].MonikerString);
videosource.NewFrame += new NewFrameEventHandler(videosource_NewFrame);
videosource.Start();
}
}
private void startbtn_Click(object sender, EventArgs e)
{
if (videosource.IsRunning)
{
videosource.Stop();
}
else
{
videosource = new VideoCaptureDevice(videoDevices[drvrlist.SelectedIndex].MonikerString);
videosource.NewFrame += new NewFrameEventHandler(videosource_NewFrame);
videosource.Start();
}
}
private void videosource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
//throw new NotImplementedException();
}
private void save_btn_Click(object sender, EventArgs e)
{
SaveFileDialog savefilediag = new SaveFileDialog();
savefilediag.Filter = "Portable Network Graphics|.png";
if(savefilediag.ShowDialog()== System.Windows.Forms.DialogResult.OK)
{
if (pictureBox1.Image != null)
{
//Save First
Bitmap varBmp = new Bitmap(pictureBox1.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Save(savefilediag.FileName, ImageFormat.Png);
//Now Dispose to free the memory
varBmp.Dispose();
varBmp = null;
pictureBox1.Image = null;
pictureBox1.Invalidate();
}
else
{ MessageBox.Show("null exception"); }
}
}
You can use the Clone method to overwrite an instance of your picturebox's image with a subspace of the image.
Bitmap varBmp = new Bitmap(pictureBox1.Image);
varBmp = varBmp.Clone(new RectangleF(0, 0, 400, 400), varBmp.PixelFormat);
From there, you can go ahead and save it to a file.
varBmp.Save(savefilediag.FileName, ImageFormat.Png);

how to clear memory of WritableBitmap

I am picking image from gallery using PhotoChooserTask, here is my setup
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
PhotoChooserTask photo = new PhotoChooserTask();
photo.Completed += photo_Completed;
photo.Show();
}
void photo_Completed(object sender, PhotoResult e)
{
if (e.ChosenPhoto != null)
{
WriteableBitmap wbmp1 = PictureDecoder.DecodeJpeg(e.ChoosenPhoto, (int)scrnWidth, (int)scrnHeight);
ImageBrush iBru = new ImageBrush();
iBru.ImageSource = wbmp1;
iBru.Stretch = Stretch.Fill;
ContentPanel.Background = iBru;
}
}
Problem: with this way is it works only with .JPEG images
to make it work with other image formats, I tried this:
void photo_Completed(object sender, PhotoResult e)
{
if (e.ChosenPhoto != null)
{
WriteableBitmap wBmp = new WriteableBitmap(0, 0);//6930432
wBmp.SetSource(e.ChosenPhoto);//23105536
MemoryStream tmpStream = new MemoryStream();//23105536
wBmp.SaveJpeg(tmpStream, (int)scrnWidth, (int)scrnHeight, 0, 100);//22831104
tmpStream.Seek(0, SeekOrigin.Begin);//22831104
WriteableBitmap wbmp1 = PictureDecoder.DecodeJpeg(tmpStream, (int)scrnWidth, (int)scrnHeight);//24449024
ImageBrush iBru = new ImageBrush();//24449024
iBru.ImageSource = wbmp1;//24449024
iBru.Stretch = Stretch.Fill;
ContentPanel.Background = iBru;
}
}
this way works with different image formats, but it is not memory efficient.
I have mentioned number of bytes used after each line for better understanding.
Question: In latter code snippet, I do not need wbmp anymore, How can I clear memory used by wbmp object?
As #Soonts suggested I used BitmapImage and it solves my purpose,
BitmapImage bmp = new BitmapImage();
bmp.DecodePixelWidth = (int)scrnWidth;
bmp.DecodePixelHeight = (int)scrnHeight;
bmp.SetSource(e.ChosenPhoto);
It consumes less memory and we can scale down image
Get rid of the WriteableBitmap, instead do something like this:
var bmp = new System.Windows.Media.Imaging.BitmapImage();
bmp.SetSource( e.ChosenPhoto );
var ib = new ImageBrush() { ImageSource = bmp, Stretch = Stretch.Fill };
ContentPanel.Background = ib;

display an image from file in wpf isn't working?

I have a button b3 and an image named pictureBox1 . Im using WPF, however I'm using the winforms openFileDialog instead of the one that comes with WPF :
below is the code that I put inside the click event of my button :
private void b3_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog openDialogIcon = new System.Windows.Forms.OpenFileDialog();
if (openDialogIcon.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
Image i = new Image();
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(openDialogIcon.FileName, UriKind.Absolute);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
i.Source = src;
i.Stretch = Stretch.Uniform;
//int q = src.PixelHeight; // Image loads here
}
}
When I click the button and select an icon. The icon doesn't appear in the pictureBox1.
Can someone please explain why the code above doesn't show the icon inside the pictureBox?
You need to assign your image to the pictureBox, else you wont see it on your screen and you only made the image object in memory.
private void b3_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog openDialogIcon = new System.Windows.Forms.OpenFileDialog();
if (openDialogIcon.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(openDialogIcon.FileName, UriKind.Absolute);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
pictureBox1.Source = src;
}
}
Try to drag and drop a Image control in your window
...
//imageStretch <- the name of Image control
i.Stretch = Stretch.Uniform;
//int q = src.PixelHeight; // Image loads here
imageStretch.Source = src;
...

Categories