Out Of Memory exception if files to big - asp.net

I'm currently working on a data-check for images. I need to request the Size (width & height) and the resolution of the image. Files over 70MB throw an "out of memory" exception on GDI Problem. Is there an alternative way to get the file-information? The same error on parse it through FromStream...
Using myfile = Image.FromFile(filePath)
...
End Using

You can use the following code to get image properties (it loads metadata only):
using (var fs = new FileStream(#"C:\Users\Dmitry\Pictures\blue-earth-wallpaper.jpg", FileMode.Open, FileAccess.Read)) {
var decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
var size = decoder.Frames[0].PixelWidth;
var height = decoder.Frames[0].PixelHeight;
var dpiX = decoder.Frames[0].DpiX;
var dpiY = decoder.Frames[0].DpiY;
}

I found this link http://www.fastgraph.com/help/image_file_header_formats.html that tells where in the file you can find the type and its dimensions. I guess, if you use something like this below to seek and get the first few bytes and close once you are done, shouldnt be using much resources
Untested code below...
// This really needs to be a member-level variable;
private static readonly object fsLock = new object();
// Instantiate this in a static constructor or initialize() method
private static FileStream fs = new FileStream("myFile.txt", FileMode.Open);
public string ReadFile(int fileOffset) {
byte[] buffer = new byte[bufferSize];
int arrayOffset = 0;
lock (fsLock) {
fs.Seek(fileOffset, SeekOrigin.Begin);
int numBytesRead = fs.Read(bytes, arrayOffset , bufferSize);
// Typically used if you're in a loop, reading blocks at a time
arrayOffset += numBytesRead;
}
// Do what you want to the byte array and close
}

Related

Generate QR code image stream or bytes for Xamarin Forms

I am struggling big time with generating QR barcodes as a byte[] or Stream (something that I can use on a XAML image source)
ZXING.NET
I've tried with Zxing.Net but I find the documentation is not great.
In fact, when installing in the xamarin forms class library I am able to compile, but as soon as I add some code to write barcodes I get a compilation error saying that
Can not resolve reference: `zxing`, referenced by `MyXamarinFormsClassLibrary`. Please add a NuGet package or assembly reference for `zxing`, or remove the reference to `Sasw.AforoPass`. 0
Something funky is going on with that library.
And I'm doing a simple example such as:
var options = new QrCodeEncodingOptions
{
DisableECI = true,
CharacterSet = "UTF-8",
Width = 250,
Height = 250
};
var writer = new BarcodeWriter<Image>();
writer.Format = BarcodeFormat.QR_CODE;
writer.Options = options;
var result = writer.Write("foo");
MyImage.Source = result.Source;
QRCoder
It's another nuget library. I've successfully used for dotnet core applications, but it does not seem to be compatible with Xamarin Forms (or Mono, or whatever). It says that the platform is not supported. Probably because it uses System.Drawing.Common?
ZXing.Net.Mobile.Forms
I've used this other library which underneath it uses ZXing.Net. What I don't like is that I don't know if there's any way to generate qr codes without relying on Xaml or the ZXingBarcodeImageView.
I managed to generate QR Codes that way as a workaround, but I hit another wall. See https://github.com/Redth/ZXing.Net.Mobile/issues/908 in which I describe the problems I have to embed the ZXingBarcodeImageView in a carousel inside a popup.
So basically I wanted to go back to the roots, and simply have a working example with the latest version of ZXing.Net (or an alternative, if it exists) that I am able to use in Xamarin Forms.
Most of the examples I find talk about BarcodeWriter but there is no such a class anymore. There is a generic one BarcodeWriter<TUnknownType>and a BarcodeWriterGeneric but as I said, I could not compile anything using Zxing.Net library and with through ZXing.Net.Mobile the images I generate are always empty.
Any help or "modern" code sample (ideally with an alternative) would be much appreciated
UPDATE 1
In other words, I'm looking to have in Xamarin Forms something similar to this code that I had using QrCoder library.
public class QrCodeService
: IQrCodeService
{
public Stream GetQrCode(Guid id, string mimeType = "image/jpeg")
{
if (mimeType is null)
{
throw new ArgumentNullException(nameof(mimeType));
}
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(id.ToString(), QRCodeGenerator.ECCLevel.Q);
var qrCode = new QRCode(qrCodeData);
var qrCodeImage = qrCode.GetGraphic(20);
var myImageCodecInfo = GetEncoderInfo(mimeType);
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
var stream = new MemoryStream();
qrCodeImage.Save(stream, myImageCodecInfo, myEncoderParameters);
stream.Position = 0;
return stream;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
var encoders = ImageCodecInfo.GetImageEncoders();
foreach (var encoder in encoders)
{
if (encoder.MimeType == mimeType)
{
return encoder;
}
}
throw new KeyNotFoundException($"Encoder for {mimeType} not found");
}
}
The solution uses QrCoder library and it works fine for Xamarin Forms as follows.
private byte[] GetQrImageAsBytes()
{
var randomText = Guid.NewGuid().ToString();
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(randomText, QRCodeGenerator.ECCLevel.L);
var qRCode = new PngByteQRCode(qrCodeData);
var qrCodeBytes = qRCode.GetGraphic(20);
return qrCodeBytes;
}
Here a working sample with this implementation
QrCoder library can do this, but instead of using as in the main page of the project:
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData); // This point onwards is problematic
Bitmap qrCodeImage = qrCode.GetGraphic(20); // This will throw not supported exception
Switch the last 2 lines to:
var qrCode = new PngByteQRCode(qrCodeData);
byte[] imageByteArray = qrCode.GetGraphic(20);
You'll get byte array instead, but you can convert it into Stream or whatever you like afterwards.

Image resizing script is not returning a proper stream for further handling

Current project:
ASP.NET 4.5.2
MVC 5
I am trying to leverage the TinyPNG API, and if I just pipe the image over to it, it works great. However, since the majority of users will be on a mobile device, and these produce images at a far higher resolution than what is needed, I am hoping to reduce the resolution of these files prior to them being piped over to TinyPNG. It is my hope that these resized images will be considerably smaller than the originals, allowing me to conduct a faster round trip.
My code:
public static async Task<byte[]> TinyPng(Stream input, int aspect) {
using(Stream output = new MemoryStream())
using(var png = new TinyPngClient("kxR5d49mYik37CISWkJlC6YQjFMcUZI0")) {
ResizeImage(input, output, aspect, aspect); // Problem area
var result = await png.Compress(output);
using(var reader = new BinaryReader(await (await png.Download(result)).GetImageStreamData())) {
return reader.ReadBytes(result.Output.Size);
}
}
}
public static void ResizeImage(Stream input, Stream output, int newWidth, int maxHeight) {
using(var srcImage = Image.FromStream(input)) {
var newHeight = srcImage.Height * newWidth / srcImage.Width;
if(newHeight > maxHeight) {
newWidth = srcImage.Width * maxHeight / srcImage.Height;
newHeight = maxHeight;
}
using(var newImage = new Bitmap(newWidth, newHeight))
using(var gr = Graphics.FromImage(newImage)) {
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
newImage.Save(output, ImageFormat.Jpeg);
}
}
}
So the ResizeArea is supposed to accept a stream and output a stream, meaning that the TinyPNG .Compress() should work just as well with the output as it would with the original input. Unfortunately, only the .Compress(input) works -- with .Compress(output) TinyPNG throws back an error:
400 - Bad Request. InputMissing, File is empty
I know TinyPNG has its own resizing routines, but I want to do this before the image is sent out over the wire to TinyPNG so that file size (and therefore transmission time) is reduced as much as possible prior to the actual TinyPNG compression.
…Aaaaand I just solved my problem by using another tool entirely.
I found ImageProcessor. Documentation is a royal b**ch to get at because it only comes in a Windows *.chm help file (it’s not online… cue one epic Whisky. Tango. Foxtrot.), but after looking at a few examples it did solve my issue quite nicely:
public static async Task<byte[]> TinyPng(Stream input, int aspect) {
using(var output = new MemoryStream())
using(var png = new TinyPngClient("kxR5d49mYik37CISWkJlC6YQjFMcUZI0")) {
using(var imageFactory = new ImageFactory()) {
imageFactory.Load(input).Resize(new Size(aspect, 0)).Save(output);
}
var result = await png.Compress(output);
using(var reader = new BinaryReader(await (await png.Download(result)).GetImageStreamData())) {
return reader.ReadBytes(result.Output.Size);
}
}
}
and everything is working fine now. Uploads are much faster now as I am not piping a full-sized image straight through to TinyPNG, and since I am storing both final-“full”-sized images as well as thumbnails straight into the database, I am now not piping the whole bloody image twice.
Posted so that other wheel-reinventing chuckleheads like me will actually have something to go on.

How does one use a memory stream instead of files when rendering Direct2D images via SharpDX?

The setup
Consider the given scratch program that uses SharpDX, a managed wrapper for Direct* libraries, to render a bitmap and save it as a PNG:
namespace ConsoleApplication5
{
using System;
using System.Diagnostics;
using System.IO;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using SharpDX.DXGI;
using SharpDX.IO;
using SharpDX.WIC;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Bitmap = SharpDX.WIC.Bitmap;
using D2DPixelFormat = SharpDX.Direct2D1.PixelFormat;
using WicPixelFormat = SharpDX.WIC.PixelFormat;
class Program
{
static void Main(string[] args)
{
var width = 400;
var height = 100;
var pixelFormat = WicPixelFormat.Format32bppBGR;
var wicFactory = new ImagingFactory();
var dddFactory = new SharpDX.Direct2D1.Factory();
var dwFactory = new SharpDX.DirectWrite.Factory();
var wicBitmap = new Bitmap(
wicFactory,
width,
height,
pixelFormat,
BitmapCreateCacheOption.CacheOnLoad);
var renderTargetProperties = new RenderTargetProperties(
RenderTargetType.Default,
new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown),
0,
0,
RenderTargetUsage.None,
FeatureLevel.Level_DEFAULT);
var renderTarget = new WicRenderTarget(
dddFactory,
wicBitmap,
renderTargetProperties)
{
TextAntialiasMode = TextAntialiasMode.Cleartype
};
renderTarget.BeginDraw();
var textFormat = new TextFormat(dwFactory, "Consolas", 48)
{
TextAlignment = TextAlignment.Center,
ParagraphAlignment = ParagraphAlignment.Center
};
var textBrush = new SolidColorBrush(
renderTarget,
Colors.Blue);
renderTarget.Clear(Colors.White);
renderTarget.DrawText(
"Hi, mom!",
textFormat,
new RectangleF(0, 0, width, height),
textBrush);
renderTarget.EndDraw();
var stream = new WICStream(
wicFactory,
"test.png",
NativeFileAccess.Write);
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(stream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare;
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();
frameEncoder.Dispose();
encoder.Dispose();
stream.Dispose();
Process.Start(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "test.png")));
}
}
}
Running this program gives you a "test.png" file in the program's working directory with the following beautiful image:
The question
Awesome, I've just rendered an image using Direct2D instead of GDI+, which is supposedly more supported in the context of an ASP.NET application. Plus, Direct2D is the new hotness.
Let's say that I wanted to write a function that rendered such an image and returned the PNG as a Stream or a byte[] array, performing the entire rendering and encoding operation in memory instead of writing to the file system. This is for a responding to a Web request; makes sense just to stream it out straight to the browser without going through the file system.
In GDI+, I could do this with a MemoryStream pretty easily, but I can't figure out how to use DataStream in SharpDX to my advantage without knowing the size of the buffer:
var bufferSize = 1024 * 3; // how do I know?
var buffer = new DataStream(
bufferSize,
true,
true);
var stream = new WICStream(
wicFactory,
buffer);
Do I have to P/Invoke to CreateStreamOnHGlobal and use that IntPtr to build my DataStream?
Is there some overload of DataStream that I am missing?
Is there an easy way to pre-calculate the necessary buffer needed to hold the encoded PNG image?
Or should I just get over going through the file system?
Thanks for any help!
The author of the library added this as a feature.
I'll leave the question around as I think the code provides a useful Direct2D sample for people.
If anyone is looking to do this in asp.net:
var memStream = new MemoryStream();
var wicStream = new WICStream(wicFactory, memStream);
//Encode wic bitmap
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(wicStream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
var format = WicPixelFormat.FormatDontCare;
frameEncoder.SetPixelFormat(ref format);
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();
//Clean-up
frameEncoder.Dispose();
encoder.Dispose();
wicStream.Dispose();
imgBackdrop.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(memStream.ToArray(), 0, memStream.ToArray().Length);

how to get the image dimesion without using bitmap or graphics object in .net

i want to create SQL CLR integrated function from Visual C#, now my requirement is user will pass a folder path as a paramter, and the function should get all the image file from the the folder, and get its basic property like FileSize, dimension etc.. but it seems SQL project does not supports System.Drawing Namespace... as i created the same function in normal project it worked fine, as i was able to use System.Drawing Namespace, but here i cannot use, System.Drawing Namespace.. so is there any other way to get the image dimension...
below is the code i have used in my normal project.
public DataTable InsertFile(string FolderPath)
{
DataTable dt = new DataTable();
DataColumn[] col = new DataColumn[] { new DataColumn("FileName", typeof(System.String)), new DataColumn("FileSize", typeof(System.Int32)), new DataColumn("FilePath", typeof(System.String)), new DataColumn("Width", typeof(System.Int32)), new DataColumn("Height", typeof(System.Int32)) };
dt.Columns.AddRange(col);
FileInfo info= null;
Bitmap bmp = null;
foreach (String s in Directory.GetFiles(FolderPath, "*.jpg"))
{
info = new FileInfo(s);
bmp = new Bitmap(s);
DataRow dr = dt.NewRow();
dr["FileName"] = Path.GetFileName(s);
dr["FileSize"] = info.Length / 1024;
dr["FilePath"] = s;
dr["Width"] = bmp.Width;
dr["Height"] = bmp.Height;
dt.Rows.Add(dr);
}
return dt;
}
does anyone have any idea how to get image dimension without using System.Drawing Namespace.
wow never seen anyone try this before, but if using Drawing in a SQL project isn't allowed try reading the header info like this http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
Edit included the code, with the change to remove the dependency on Size.
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
ushort chunkLength = binaryReader.ReadLittleEndianInt16();
if (marker == 0xc0)
{
binaryReader.ReadByte();
int height = binaryReader.ReadLittleEndianInt16();
int width = binaryReader.ReadLittleEndianInt16();
return new int[] { width, height };
}
binaryReader.ReadBytes(chunkLength - 2);
}
Is the Image object any better for you?
System.Drawing.Image forSize = System.Drawing.Image.FromFile(s);
dr["Width"] = forSize.Width;
and so forth.
That any better or same problem?

Pause and resume download in flex?

Is it possible in an air application to start a download, pause it and after that resume it?
I want to download very big files (1-3Gb) and I need to be sure if the connection is interrupted, then the next time the user tries to download the file it's start from the last position.
Any ideas and source code samples would be appreciated.
Yes, you would want to use the URLStream class (URLLoader doesn't support partial downloads) and the HTTP Range header. Note that there are some onerous security restrictions on the Range header, but it should be fine in an AIR application. Here's some untested code that should give you the general idea.
private var _us:URLStream;
private var _buf:ByteArray;
private var _offs:uint;
private var _paused:Boolean;
private var _intervalId:uint;
...
private function init():void {
_buf = new ByteArray();
_offs = 0;
var ur:URLRequest = new URLRequest( ... uri ... );
_us = new URLStream();
_paused = false;
_intervalId = setInterval(500, partialLoad);
}
...
private function partialLoad():void {
var len:uint = _us.bytesAvailable;
_us.readBytes(_buf, _offs, len);
_offs += len;
if (_paused) {
_us.close();
clearInterval(_intervalId);
}
}
...
private function pause():void {
_paused = true;
}
...
private function resume():void {
var ur:URLRequest = new URLRequest(... uri ...);
ur.requestHeaders = [new URLRequestHeader("Range", "bytes=" + _offs + "-")];
_us.load(ur);
_paused = false;
_intervalId = setInterval(500, partialLoad);
}
if you are targeting mobile devices, maybe you should take a look at this native extension: http://myappsnippet.com/download-manager-air-native-extension/ it supports simultaneous resumable downloads with multi-section chunks to download files as fast as possible.

Resources