I'm trying to add text to a video. I've been using the Accord framework so far, and this is what I currently have:
using (var vFReader = new VideoFileReader())
{
vFReader.Open(#"\video.mp4");
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(#"\video2.mp4", vFReader.Width, vFReader.Height, vFReader.FrameRate, VideoCodec.MPEG4, vFReader.BitRate);
for (var i = 0; i < vFReader.FrameCount; i++)
{
var image = vFReader.ReadVideoFrame();
var graphics = Graphics.FromImage(image);
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawString("Custom text", font, Brushes.White, new Point(vFReader.Width / 2, 25), format);
graphics.Flush();
vFWriter.WriteVideoFrame(image, (uint)i);
}
vFWriter.Flush();
}
}
This is technically working, but the resulting video is in very poor quality compared to the original. What am I doing wrong?
Here is the difference in quality.
Original video:
Edited video:
Related
I am trying to print 40x40mm labels from a programmatically created image.
The label must have text on it, and a logo. Since the label is fairly small I am finding myself fiddling with how to do proper smooting, antialias and such.
I have tried multipl settings but I am not sure it's even the right way to go about it.
First I draw the container Bitmap:
private Bitmap DrawLabelCircle()
{
var labelImage = new Bitmap(152, 152);
using (Graphics gfx = Graphics.FromImage(labelImage))
{
var pen = new Pen(Color.Black, 1);
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.DrawEllipse(pen, 1, 1, 150, 150);
}
return labelImage;
}
Then I overlay different text snippets on that container Bitmap
private Bitmap DrawDistributorTextRectangle(string text)
{
var bitmap = new Bitmap(113, 113);
var rectangle = new Rectangle(0, 0, 110, 110);
using (Graphics gfx = Graphics.FromImage(bitmap))
{
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
var font = new Font(FontFamily.GenericSansSerif, 5, FontStyle.Regular, GraphicsUnit.Point);
var brush = new SolidBrush(Color.Black);
gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
gfx.DrawString(text, font, brush, rectangle);
}
bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
return bitmap;
}
Overlay that text on the previous created Bitmap.
private Bitmap DistributorTextOverlay(Bitmap source, Bitmap overlay)
{
var result = new Bitmap(source.Width, source.Height);
var graphics = Graphics.FromImage(result);
graphics.CompositingMode = CompositingMode.SourceOver;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(source, 0, 0);
graphics.DrawImage(overlay, 120, 0);
return result;
}
And the I save it.
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => encoder.MimeType == "image/png");
var encoderInfo = new EncoderParameters() { Param = { [0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L) } };
image.SetResolution(203, 203);
image.Save("img.png", imageCodecInfo, encoderInfo);
The big challenge here is that the image I get is actually looking alright, all things considered.
But when I print it, it looks terrible pixelated.
I would really like to give some pointers for what settings I should apply to all these bitmaps before saving the final result, and what settings should apply for the final image I save.
I am by no means a .NET graphics expert so all help is much appreciated.
40mm is 1.5748 inches. So if you plan to print it at 300 dpi resolution, your bitmap should be 1.5748*300 = 472 pixels instead of 152.
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);
When I take a screenshot of a current WPF window, the image resolution is that of my monitor (if the app is maximized), which is ok. However, if I was to print that image to a much bigger format, the image would look blurry. I found the way to capture the current window, and save it as a png file, but it's not doing the trick. The image is saved with the resolution I set, but the actual wpf window takes only a small portion of the saved image. Example is taken from:
http://blogs.msdn.com/b/saveenr/archive/2008/09/18/wpf-xaml-saving-a-window-or-canvas-as-a-png-bitmap.aspx
var screen = System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
var rtb = new RenderTargetBitmap(4000, 4000, 96, 96, PixelFormats.Pbgra32);
rtb.Render(screen);
var enc = new System.Windows.Media.Imaging.PngBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb));
using (var stm = System.IO.File.Create("ScreenShot.png"))
{
enc.Save(stm);
using (Image img = Image.FromStream(stm))
{
Rectangle dest = new Rectangle(0, 0, 6000, 4000);
using (Graphics imgG = Graphics.FromImage(img))
{
imgG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
imgG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
imgG.DrawImage(img, dest);
}
img.Save("NewScreenShot.png");
}
}
So basically, I'd like to capture the screenshot with the resolution of 4000 x 4000, if that's possible, without losing quality.
The above code produces an image of 4000 x 4000, however the screenshot only takes a small portion of it, its original resolution.
To scale your image, you can use a DrawingVisual and a ScaleTransform :
var w = 4000;
var h = 4000;
var screen = System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(screen),
null,
new Rect(new Point(), new Size(screen.Width, screen.Height)));
}
visual.Transform = new ScaleTransform(w / screen.ActualWidth, h / screen.ActualHeight);
var rtb = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Pbgra32);
rtb.Render(visual);
var enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(rtb));
using (var stm = File.Create("ScreenShot.png"))
{
enc.Save(stm);
}
I want to create a default avatar image which is a circle with initials in it. I want to do this on the server side as a png. Is this possible using the .net graphics library?
I ended up doing this. Thanks for pointing me in the right direction TaW
public ActionResult Avatar()
{
using (var bitmap = new Bitmap(50, 50))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.Clear(Color.White);
using (Brush b = new SolidBrush(ColorTranslator.FromHtml("#eeeeee")))
{
g.FillEllipse(b, 0, 0, 49, 49);
}
float emSize = 12;
g.DrawString("AM", new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular),
new SolidBrush(Color.Black), 10, 15);
}
using (var memStream = new System.IO.MemoryStream())
{
bitmap.Save(memStream, System.Drawing.Imaging.ImageFormat.Png);
var result = this.File(memStream.GetBuffer(), "image/png");
return result;
}
}
}
I am creating a portfolio site for a photographer.
I am faced with the problem of resizing photos from large to small. If I reduce the size much of the quality is lost. How can I compress the picture in order not to lose quality?
My code:
using (var input = new Bitmap(imageFile.InputStream))
{
int width;
int height;
if (input.Width > input.Height)
{
width = 411 * input.Width / input.Height;
height = 411;
}
else
{
height = 411;
width = 411 * input.Width / input.Height;
}
using (var thumb = new Bitmap(width, height))
using (var graphic = Graphics.FromImage(thumb))
{
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.AntiAlias;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.DrawImage(input, 0, 0, width, height);
using (var output = System.IO.File.Create(imagePath))
{
thumb.Save(output, ImageFormat.Jpeg);
}
}
}
You may get better results doing gradual resizing (like 10-25% each step). Try also saving in loss-less format (like ImageFormat.Png).
If quality is extremely important manual conversion in proper photo editing tool is probably the right approach.