I'm trying to render some text and an image to a writeable bitmap to make 1 larger image, and this method has worked in other locations for creating or manipulating images, but for some reason, this instance is only creating a black image. If I just set the image source to the original WriteableBitmap, it shows just fine, but when I call SaveJpeg and then LoadJpeg, it shows as a black image (and yes, I need to call SaveJpeg since this is actually getting passed up to a server). The following is how I'm trying to render the elements:
NoteViewModel note = Instance.Note;
var grid = new Grid()
{
Height = 929,
Width = 929
};
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(679) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
var noteText = new TextBlock()
{
Text = note.Text,
FontFamily = note.FontFamily,
Foreground = note.FontColor,
TextWrapping = System.Windows.TextWrapping.Wrap,
Width = 929,
Height = 679
};
Grid.SetRow(noteText, 0);
grid.Children.Add(noteText);
WriteableBitmap sigImage = Instance.Signature.SignatureImage;
var sig = new Image()
{
Source = sigImage,
Height = 250,
Width = (sigImage.PixelWidth / sigImage.PixelHeight) * 250,
Margin = new Thickness(929 - ((sigImage.PixelWidth / sigImage.PixelHeight) * 250), 0, 0, 0)
};
Grid.SetRow(sig, 1);
grid.Children.Add(sig);
var messagePicture = new WriteableBitmap(grid, null);
var stream = new MemoryStream();
messagePicture.SaveJpeg(stream, messagePicture.PixelWidth, messagePicture.PixelHeight, 0, 100); //Save to a temp stream
stream.Position = 0;
var test = new WriteableBitmap(929,929); //Load the picture back up to see it
test.LoadJpeg(stream);
img.Source = test; //Show the image on screen (img is an Image element)
So apparently WriteableBitmap will render a transparent background as black when calling SaveJpeg, so I solved this by rendering a white canvas as well, like so:
var background = new Canvas()
{
Width = 929,
Height = 929,
Background = new SolidColorBrush(Colors.White)
};
messagePicture.Render(background, new TranslateTransform());
Related
I am trying to add different page contents in order to pass it to the Print Manager interface. However, when trying to add multiple BitmapImages, it's returning a "Element is already the child of another element." error.
Here's what my current code looks like:
Canvas page = new Canvas
{
Width = pageDescription.PageSize.Width,
Height = pageDescription.PageSize.Height
};
Canvas viewablePage = new Canvas()
{
Width = pageDescription.ViewablePageSize.Width,
Height = pageDescription.ViewablePageSize.Height
};
viewablePage.SetValue(Canvas.LeftProperty, pageDescription.Margin.Width);
viewablePage.SetValue(Canvas.TopProperty, pageDescription.Margin.Height);
// The image "frame" which also acts as a viewport
Grid photoView = new Grid
{
Width = pageDescription.PictureViewSize.Width,
Height = pageDescription.PictureViewSize.Height
};
The foreach loop wherein a different image is added to the a different page
foreach(var btm in bitmapImages)
{
Image image = new Image
{
Source = btm,
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center
};
// Use the real image size when croping or if the image is smaller then the target area (prevent a scale-up).
if ((btm.PixelWidth <= pageDescription.PictureViewSize.Width &&
btm.PixelHeight <= pageDescription.PictureViewSize.Height))
{
image.Stretch = Stretch.None;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
}
photoView.Children.Add(image);
viewablePage.Children.Add(photoView);
page.Children.Add(viewablePage);
pages.Add(page);
}
bitmapImages is a list of bitmaps. It works if there's only one image to be added but when adding < 1 image to a page, it returns the error. Do you have any suggestions on how should I implement this?
Thanks alot.
Each UI element in UWP can only be used in the UI in one place at one time.
You need to define the UI element every loop.
foreach(var btm in bitmapImages)
{
Canvas page = new Canvas
{
Width = pageDescription.PageSize.Width,
Height = pageDescription.PageSize.Height
};
Canvas viewablePage = new Canvas()
{
Width = pageDescription.ViewablePageSize.Width,
Height = pageDescription.ViewablePageSize.Height
};
viewablePage.SetValue(Canvas.LeftProperty, pageDescription.Margin.Width);
viewablePage.SetValue(Canvas.TopProperty, pageDescription.Margin.Height);
// The image "frame" which also acts as a viewport
Grid photoView = new Grid
{
Width = pageDescription.PictureViewSize.Width,
Height = pageDescription.PictureViewSize.Height
};
Image image = new Image
{
Source = btm,
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center
};
// Use the real image size when croping or if the image is smaller then the target area (prevent a scale-up).
if ((btm.PixelWidth <= pageDescription.PictureViewSize.Width &&
btm.PixelHeight <= pageDescription.PictureViewSize.Height))
{
image.Stretch = Stretch.None;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
}
photoView.Children.Add(image);
viewablePage.Children.Add(photoView);
page.Children.Add(viewablePage);
pages.Add(page);
}
I am having difficulties in exporting LiveCharts PieChart to a .png file.
So far what I have done is trying to draw the control to a bitmap (DrawToBitmap), but it is just outputting a black image. I have discarded other alternatives such as screenshots because the chart is not created to be deployed in a custom form for visualization. Its main purpose is just graphic statistic exporting.
This is my main code:
LiveCharts.WinForms.PieChart chart = initializePieChart2DFolder(true);
Bitmap bmp = new Bitmap(chart.Width, chart.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
chart.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height));
bmp.Save("graphFolder.png", System.Drawing.Imaging.ImageFormat.Png);
This is the method I use to create the Pie chart:
private LiveCharts.WinForms.PieChart initializePieChart2DFolder()
{
LiveCharts.WinForms.PieChart chart = new LiveCharts.WinForms.PieChart();
chart.Anchor = System.Windows.Forms.AnchorStyles.None;
chart.Location = new System.Drawing.Point(17, 56);
chart.Name = "pieChart2DFolder";
chart.Size = new System.Drawing.Size(364, 250);
chart.TabIndex = 0;
chart.BackColorTransparent = false;
chart.BackColor = Color.White;
chart.ForeColor = Color.Black;
SeriesCollection chartData = new SeriesCollection();
foreach(var annot in numAnnotsPerLabel)
{
System.Windows.Media.Color newColor = System.Windows.Media.Color.FromArgb(color[annot.Key].A, color[annot.Key].R, color[annot.Key].G, color[annot.Key].B);
chartData.Add( new PieSeries { Title = annot.Key,
Values = new ChartValues<int> { annot.Value },
DataLabels = true,
Stroke = System.Windows.Media.Brushes.DimGray,
Foreground = System.Windows.Media.Brushes.Black,
FontSize = 9,
Fill = new
System.Windows.Media.SolidColorBrush(newColor)});
}
chart.Series = chartData;
DefaultLegend customLegend = new DefaultLegend();
customLegend.BulletSize = 15;
customLegend.Foreground = System.Windows.Media.Brushes.Black;
customLegend.Orientation = System.Windows.Controls.Orientation.Vertical;
customLegend.FontSize = 10;
chart.DefaultLegend = customLegend;
chart.LegendLocation = LegendLocation.Right;
var tooltip = chart.DataTooltip as DefaultTooltip;
tooltip.SelectionMode = LiveCharts.TooltipSelectionMode.OnlySender;
return chart;
}
Thank you very much in advance!
This might be a silly question, but I was wondering if it's possible to display a document in WPF's DocumentViewer control from a byte array.
If not, could someone provide an example of how the control is normally used to display a document? I can't seem to find a decent example.
It is about arranging different UIElements:
FixedDocument fixedDocument = new FixedDocument();
DocumentViewer dv = new DocumentViewer() { Document = fixedDocument };
this.Content = dv;
var page1 = new FixedPage() { Width = 600, Height = 800 };
PageContent page1Content = new PageContent() { Child = page1 };
var sp = new StackPanel();
sp.Children.Add(new TextBlock
{
Text = "Title",
FontSize = 30,
Margin = new Thickness(100, 50, 0, 70)
});
sp.Children.Add(new TextBlock
{
Text = "The quick brown fox jumps over the lazy dog...",
FontSize = 15,
Margin = new Thickness(10, 0, 0, 10)
});
Rectangle rect = new Rectangle();
rect.Width = 150;
rect.Height = 150;
rect.Fill = Brushes.Black;
sp.Children.Add(new Rectangle
{
Width = 150,
Height = 150,
Fill = Brushes.Black
});
page1.Children.Add(sp);
fixedDocument.Pages.Add(page1Content);
I have made an application which generates me a QR Code in a PNG image, but now I have to insert the text from QR Code next to the QR Code image.
I don't have any experience using ZXing Library but I'm thinking that it may contain an option for this...
Example:
Code:
namespace QR_Code_with_WFA
{
public void CreateQRImage(string inputData)
{
if (inputData.Trim() == String.Empty)
{
System.Windows.Forms.MessageBox.Show("Data must not be empty.");
}
BarcodeWriter qrcoder = new ZXing.BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new ZXing.QrCode.QrCodeEncodingOptions
{
ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H,
Height = 250,
Width = 250
}
};
string tempFileName = System.IO.Path.GetTempPath() + inputData + ".png";
Image image;
String data = inputData;
var result = qrcoder.Write(inputData);
image = new Bitmap(result);
image.Save(tempFileName);
System.Diagnostics.Process.Start(tempFileName);
}
}
Well, ZXing.BarcodeWriter.Options has property PureBarcode, which will put source text into generated image when set to false.
Unfortunately it has no effect when format of barcode is BarcodeFormat.QR_CODE (and it is by design).
But you can draw your text manually after you've generated barcode image:
var result = qrcoder.Write(inputData);
using (var g = Graphics.FromImage(result))
using (var font = new Font(FontFamily.GenericMonospace, 12))
using (var brush = new SolidBrush(Color.Black))
using(var format = new StringFormat(){Alignment = StringAlignment.Center})
{
int margin = 5, textHeight = 20;
var rect = new RectangleF(margin, result.Height - textHeight,
result.Width - 2 * margin, textHeight);
g.DrawString(inputData, font, brush, rect, format);
}
result.Save(tempFileName);
Note you can select your own font size and fontfamily which will better suite your goals.
Update:
In the case you're trying to place text to the right from image - you have to "extend" to the right your generated image first, and then draw text:
var result = qrcoder.Write(inputData);
int textWidth = 200, textHeight = 20;
// creating new bitmap having imcreased width
var img = new Bitmap(result.Width + textWidth, result.Height);
using (var g = Graphics.FromImage(img))
using (var font = new Font(FontFamily.GenericMonospace, 12))
using (var brush = new SolidBrush(Color.Black))
using (var bgBrush = new SolidBrush(Color.White))
using (var format = new StringFormat() { Alignment = StringAlignment.Near })
{
// filling background with white color
g.FillRectangle(bgBrush, 0, 0, img.Width, img.Height);
// drawing your generated image over new one
g.DrawImage(result, new Point(0,0));
// drawing text
g.DrawString(inputData, font, brush, result.Width, (result.Height - textHeight) / 2, format);
}
img.Save(tempFileName);
I have the method, which is executed in Application_Deacitvated/Closing().
public bool createBackTile()
{
if(AlarmClock.IsExists())
{
ImageBrush background = new ImageBrush()
{
ImageSource = new BitmapImage(new Uri("/BackBackgroundTheme.png", UriKind.Relative)),
AlignmentX = AlignmentX.Center,
AlignmentY = AlignmentY.Center
};
// Preparing tile image.
TextBox tileImageData = new TextBox()
{
Text = AlarmClock.Read().ToShortTimeString(),
FontSize = 45,
FontWeight = FontWeights.Bold,
Foreground = new SolidColorBrush(Colors.White),
//Background = background,
Height = 173,
Width = 173,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
Padding = new Thickness(-12),
Margin = new Thickness(0),
Clip = new RectangleGeometry { Rect = new Rect(0, 0, 173, 173) }
};
Canvas canvas = new Canvas()
{
Width = 173,
Height = 173,
Background = background,
Margin = new Thickness(0)
};
canvas.Children.Add(tileImageData);
// Saving tile image.
WriteableBitmap tileImage = new WriteableBitmap(173, 173);
tileImage.Render(canvas, null);
tileImage.Render(tileImageData, null);
tileImage.Invalidate();
using(var stream = IsolatedStorageFile.GetUserStoreForApplication().CreateFile("/Shared/ShellContent/BackBackground.jpg"))
{
tileImage.SaveJpeg(stream, 173, 173, 0, 100);
}
// Sets data for tile.
StandardTileData tileData = new StandardTileData()
{
BackgroundImage = new Uri("BackgroundAlarmSet.png", UriKind.Relative),
BackBackgroundImage = new Uri(#"isostore:/Shared/ShellContent/BackBackground.jpg"),
BackContent = "",
BackTitle = "",
};
// Sets tile.
ShellTile.ActiveTiles.FirstOrDefault().Update(tileData);
return true;
}
return false;
}
So, as you can see, I want to generate tile with my text in the center of it with image background "BackBackgroundTheme.png". That tile I'm trying to save in IsolatedStorage and assign it to BackBackgroundImage.
But it doesn't work. The tile is flipping over but the BackBackground is completly black. I have loaded this manipulated background and it seems that's indeed just black box. So, how to get it working?
Try: BackgroundImage = new Uri(#"isostore:/Shared/ShellContent/BackBackground.jpg", UriKind.Absolute)
I have finally found out where the problem is.
It seems, that generation of tile image isn't done properly in Application_Closing/Deactivating(). So I moved image generation to somwhere else and now, when application is closing/deactivating, I just set previously generated image to a tile.
Try this:
canvas.Children.Add(tileImageData);
canvas.UpdateLayout();
// Saving tile image.
WriteableBitmap tileImage = new WriteableBitmap(173, 173);