I would like to create a QR code with using ZXing(0.16.4) But I meet following exception,
System.InvalidOperationException: 'You have to set a renderer
instance.'
Almost the same code works well with .Net Framework 4.6.1
here is my code
static void Main(string[] args)
{
var qrCode = CreateQrCode("test");
Console.ReadKey();
}
public static byte[] CreateQrCode(string content)
{
BarcodeWriter<Bitmap> writer = new BarcodeWriter<Bitmap>
{
Format = BarcodeFormat.QR_CODE,
Options = new QrCodeEncodingOptions
{
Width = 100,
Height = 100,
}
};
var qrCodeImage = writer.Write(content); // BOOM!!
using (var stream = new MemoryStream())
{
qrCodeImage.Save(stream, ImageFormat.Png);
return stream.ToArray();
}
}
I solved the issue, Basically I used https://www.nuget.org/packages/ZXing.Net.Bindings.CoreCompat.System.Drawing
I create BarcodeWriter generated from following namespace
ZXing.CoreCompat.System.Drawing
here is my CreateQrCode method
public static byte[] CreateQrCode(string content)
{
BarcodeWriter writer = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new QrCodeEncodingOptions
{
Width = 100,
Height = 100,
}
};
var qrCodeImage = writer.Write(content); // BOOM!!
using (var stream = new MemoryStream())
{
qrCodeImage.Save(stream, ImageFormat.Png);
return stream.ToArray();
}
}
Here is the read QR code method, maybe someone will need as well.
BarcodeReader also generated from the same namespace like create.
Here is the method
public static string ReadQrCode(byte[] qrCode)
{
BarcodeReader coreCompatReader = new BarcodeReader();
using (Stream stream = new MemoryStream(qrCode))
{
using (var coreCompatImage = (Bitmap)Image.FromStream(stream))
{
return coreCompatReader.Decode(coreCompatImage).Text;
}
}
}
Hope this answer will protect someone's hair against pulling.
There is a newer version of the package available and it works with .NET Core 3.1.
https://www.nuget.org/packages/ZXing.Net.Bindings.Windows.Compatibility/
I needed to add "Renderer = new ZXing.Rendering.BitmapRenderer()" when using ZXing.Net v0.16.6
public static byte[] CreateQrCode(string content)
{
byte[] imageData;
var qrWriter = new ZXing.BarcodeWriter<System.Drawing.Bitmap>
{
Format = BarcodeFormat.QR_CODE,
Options = new ZXing.Common.EncodingOptions { Height = 100, Width = 100, Margin = 0 },
Renderer = new ZXing.Rendering.BitmapRenderer()
};
using (var ms = new System.IO.MemoryStream())
using (System.Drawing.Bitmap pixelData = qrWriter.Write(content))
{
pixelData.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
imageData = ms.ToArray();
}
return imageData;
}
I'm currently moving to .net 6 and I used BarcodeWriter from ZXing.Net.Bindings.SkiaSharp NuGet package.
using ZXing.SkiaSharp;
var barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Height = _height,
Width = _width,
Margin = _margin
}
};
using var bitmap = barcodeWriter.Write(qrValue);
using var stream = new MemoryStream();
bitmap.Encode(stream, SKEncodedImageFormat.Png, 100);
Your stream is filled now :)
Related
I have a Razor page which I want to generate a Zip file containing multiple CSV files.
It works fine when I just want to generate one file, e.g.
public async Task<FileStreamResult> OnGet(int id)
{
var bankDetails = _paymentFileGenerator.GeneratePaymentFiles(id);
await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture)
{
Configuration = { HasHeaderRecord = false, }
};
csvWriter.WriteRecords(bankDetails);
streamWriter.Flush();
return new FileStreamResult(new MemoryStream(memoryStream.ToArray()), new MediaTypeHeaderValue("text/csv"))
{
FileDownloadName = "bacs.csv"
};
}
But when I try to pass memory streams for two files into a DotNetZip stream the zip downloads to the browser but both files are 0kb. Any thoughts on why?
public async Task<FileStreamResult> OnGet(int id)
{
var bankFiles = _paymentFileGenerator.GeneratePaymentFiles(id);
using var zipStream = new MemoryStream();
using var zip = new ZipFile();
await using var bankFileStream = new MemoryStream();
await using var bankFileStreamWriter = new StreamWriter(bankFileStream);
await using var bankFileCsvWriter = new CsvWriter(bankFileStreamWriter, CultureInfo.InvariantCulture)
{
Configuration = { HasHeaderRecord = false, }
};
bankFileCsvWriter.WriteRecords(bankFiles.BankFile);
bankFileCsvWriter.Flush();
bankFileStream.Seek(0, SeekOrigin.Begin);
zip.AddEntry("bacs.csv", (name, stream) => bankFileStream.ToArray());
await using var internalFileStream = new MemoryStream();
await using var internalFileStreamWriter = new StreamWriter(internalFileStream);
await using var internalFileCsvWriter = new CsvWriter(internalFileStreamWriter, CultureInfo.InvariantCulture);
internalFileCsvWriter.WriteRecords(bankFiles.InternalFile);
internalFileCsvWriter.Flush();
internalFileStream.Seek(0, SeekOrigin.Begin);
zip.AddEntry("internal.csv", (name, stream) => internalFileStream.ToArray());
zip.Save(zipStream);
zipStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(new MemoryStream(zipStream.ToArray()), new MediaTypeHeaderValue("application/zip"))
{
FileDownloadName = "paymentbatch.zip"
};
}
I've seen other StackOverflow posts where people suggested adding the Seek() function to reset the position of the streams but it didn't work for me whether that was there or not.
When debugging, I can see that the 'bankfileStream' stream has bytes in it when I call the zip.AddEntry() but then the zipStream shows 0 bytes when I call zip.Save(zipStream).
Any suggestions appreciated!
I tried many different options and nothing worked until I used the SharpZipLib library instead. Here is the full solution:
public async Task<FileStreamResult> OnGet(int id)
{
var bankFiles = _paymentFileGenerator.GeneratePaymentFiles(id);
var bankFileBytes = await GetCsvFileBytes(bankFiles.BankFile, includeHeader: false);
var internalFileBytes = await GetCsvFileBytes(bankFiles.InternalFile);
var files = new List<AttachedFile>
{
new AttachedFile("bacs.csv", bankFileBytes),
new AttachedFile("internal.csv", internalFileBytes)
};
var zipStream = AddFilesToZip(files);
return new FileStreamResult(zipStream, new MediaTypeHeaderValue("application/zip"))
{
FileDownloadName = "paymentbatch.zip"
};
}
public MemoryStream AddFilesToZip(List<AttachedFile> attachedFiles)
{
var outputMemStream = new MemoryStream();
using (var zipStream = new ZipOutputStream(outputMemStream))
{
// 0-9, 9 being the highest level of compression
zipStream.SetLevel(3);
foreach (var file in attachedFiles)
{
var newEntry = new ZipEntry(file.Name) {DateTime = DateTime.Now};
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(new MemoryStream(file.Bytes), zipStream, new byte[4096]);
}
zipStream.CloseEntry();
// Stop ZipStream.Dispose() from also Closing the underlying stream.
zipStream.IsStreamOwner = false;
}
outputMemStream.Position = 0;
return outputMemStream;
}
private static async Task<byte[]> GetCsvFileBytes<T>(List<T> records, bool includeHeader = true) where T : class
{
await using var bankFileStream = new MemoryStream();
await using var bankFileStreamWriter = new StreamWriter(bankFileStream);
await using var bankFileCsvWriter = new CsvWriter(bankFileStreamWriter, CultureInfo.InvariantCulture)
{
Configuration = {HasHeaderRecord = includeHeader}
};
bankFileCsvWriter.WriteRecords(records);
bankFileStreamWriter.Flush();
return bankFileStream.ToArray();
}
public class AttachedFile
{
public byte[] Bytes { get; set; }
public string Name { get; set; }
public AttachedFile(string name, byte[] bytes)
{
Bytes = bytes;
Name = name;
}
}
I got the new image successfully, but I can't get the original image, the image was cropped.
Here is the code I tried:
private byte[] ConvertToCCITT4(byte[] input)
{
MemoryStream memoryStream1 = new MemoryStream(input);
RasterCodecs.CodecsPath = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName;
RasterCodecs rasterCodecs = new RasterCodecs();
using (IRasterImage irasterImage = rasterCodecs.Load((Stream)memoryStream1))
{
MemoryStream memoryStream2 = new MemoryStream();
rasterCodecs.Save(irasterImage, (Stream)memoryStream2, (RasterImageFormat)29, 1);
return memoryStream2.ToArray();
}
}
I am trying to scale the original image to 50% and 25% and try to download the scaled image in MVC. I am using the below code which was taken from Google search.
public byte[] ScaleImageByPercent(byte[] imageBuffer, int Percent)
{
using (Stream imageStream = new MemoryStream(imageBuffer))
{
using (Image scaleImage = Image.FromStream(imageStream))
{
float scalePercent = ((float)Percent / 100);
int originalWidth = scaleImage.Width;
int originalHeight = scaleImage.Height;
int originalXPoint = 0;
int originalYPoint = 0;
int scaleXPoint = 0;
int scaleYPoint = 0;
int scaleWidth = (int)(originalWidth * scalePercent);
int scaleHeight = (int)(originalHeight * scalePercent);
using (Bitmap scaleBitmapImage = new Bitmap(scaleWidth, scaleHeight, PixelFormat.Format24bppRgb))
{
scaleBitmapImage.SetResolution(scaleImage.HorizontalResolution, scaleImage.VerticalResolution);
Graphics graphicImage = Graphics.FromImage(scaleBitmapImage);
graphicImage.CompositingMode = CompositingMode.SourceCopy;
graphicImage.InterpolationMode = InterpolationMode.NearestNeighbor;
graphicImage.DrawImage(scaleImage,
new Rectangle(scaleXPoint, scaleYPoint, scaleWidth, scaleHeight),
new Rectangle(originalXPoint, originalYPoint, originalWidth, originalHeight),
GraphicsUnit.Pixel);
graphicImage.Dispose();
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(scaleBitmapImage, typeof(byte[]));
}
}
}
}
When i use 3.4MB image its returning 4.7MB in 50% and even worst in 100% its returning 18 MB.
EDIT:
After getting the byte array i am downloading the image using below code. After downloading while i check the file size in disk its showing bigger size.
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(new MemoryStream(scaledBytes));
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
Am i doing the scaling correctly?. Which one i need to change get the lower size image while scaling using above functionality.
Your code works, I believe it's just a matter of image compression, basically you are pushing your byte array to your output stream as is, while you should save it as a jpeg. In my example I use a FileStream for simplicity, in your case you should use your output stream.
Give this a try (just drop any Jpg file on the compiled executable):
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
string filePath = System.IO.Path.GetFullPath(args[0]);
byte[] originalImage = System.IO.File.ReadAllBytes(filePath);
byte[] resizedImage = ScaleImageByPercent(originalImage, 50);
using (Stream imageStream = new MemoryStream(resizedImage))
{
using (Image scaleImage = Image.FromStream(imageStream))
{
string outputPath = System.IO.Path.GetDirectoryName(filePath);
outputPath = System.IO.Path.Combine(outputPath, $"{System.IO.Path.GetFileNameWithoutExtension(filePath)}_resized.jpg");
using (FileStream outputFile = System.IO.File.Open(outputPath, FileMode.Create, FileAccess.Write))
{
scaleImage.Save(outputFile, ImageFormat.Jpeg);
}
}
}
}
public static byte[] ScaleImageByPercent(byte[] imageBuffer, int Percent)
{
using (Stream imageStream = new MemoryStream(imageBuffer))
{
using (Image scaleImage = Image.FromStream(imageStream))
{
float scalePercent = ((float)Percent / 100);
int originalWidth = scaleImage.Width;
int originalHeight = scaleImage.Height;
int originalXPoint = 0;
int originalYPoint = 0;
int scaleXPoint = 0;
int scaleYPoint = 0;
int scaleWidth = (int)(originalWidth * scalePercent);
int scaleHeight = (int)(originalHeight * scalePercent);
using (Bitmap scaleBitmapImage = new Bitmap(scaleWidth, scaleHeight, PixelFormat.Format24bppRgb))
{
scaleBitmapImage.SetResolution(scaleImage.HorizontalResolution, scaleImage.VerticalResolution);
Graphics graphicImage = Graphics.FromImage(scaleBitmapImage);
graphicImage.CompositingMode = CompositingMode.SourceCopy;
graphicImage.InterpolationMode = InterpolationMode.NearestNeighbor;
graphicImage.DrawImage(scaleImage,
new Rectangle(scaleXPoint, scaleYPoint, scaleWidth, scaleHeight),
new Rectangle(originalXPoint, originalYPoint, originalWidth, originalHeight),
GraphicsUnit.Pixel);
graphicImage.Dispose();
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(scaleBitmapImage, typeof(byte[]));
}
}
}
}
}
}
Here it is the result:
EDIT:
Ok for the webapi interface try doing like this:
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
using (Stream imageStream = new MemoryStream(resizedImage))
{
using (Image scaleImage = Image.FromStream(imageStream))
{
using (MemoryStream ms = new MemoryStream())
{
scaleImage.Save(ms, ImageFormat.Jpeg);
result.Content = new StreamContent(ms);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
}
}
}
return result;
I think that we can reduce size of image by change PixelFormat type.
You can refer to this Reducing Bitmap bit-size in C#
I'm having some trouble with an implementation of the ZXing.Net.Mobile (Android) implementation in Xamarin Forms. I have the following class in my Android project which implements the IBarcodeWriter interface (which is in my Shared Project). The application isn't throwing any errors but it isn't showing an image when added into a stacklayout with DependencyService.Get<IBarcodeWriter> ().GetImage()
This is the class from my Droid project:
namespace SmartCart {
public class BarcodeGenerator : IBarcodeWriter
{
public BarcodeGenerator () {}
public Image image = new Image();
public byte[] bitmapBytes;
public String qrData (String s) {
return s;
}
public void CreateBarcode () {
image.Source = ImageSource.FromStream(() =>
{
var writer = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Height = 200,
Width = 600
}
};
var bitmapBytes = writer.Write ("Encode this to QRCode");
MemoryStream ms = new MemoryStream(bitmapBytes);
ms.Position = 0;
return ms;
});
}
public Image GetImage() {
return image;
}
}
We use following method to generate a QR-Code. (look at the bitmap.Compress row, maybe that solves your Problem):
public byte[] GenerateQrImage(string content, int width, int height)
{
var options = new QrCodeEncodingOptions
{
Height = height,
Width = width,
Margin = 0,
PureBarcode = true
};
var writer = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = options
};
// Generate bitmap
var bitmap = writer.Write(content);
if (bitmap != null)
{
// Get bytes from bitmap
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 100, stream);
return stream.ToArray();
}
}
return null;
}
Edit: It turns out, that the problem may be a wrong nuget package. use this package to generate the qr-code
Background: I am consuming a service which returns data with a MIME type of audio/wav. I need to provide a playback mechanism for this audio (currently built as an MVC application). As an example, my endpoint looks something like https://audio.fooservice.com/GetAudio?audioId=123
The audio is 8kHz, 1-channel u-law.
Due to varying format support across browsers when using the HTML5 <audio> tag, I am unable to use the original u-law wav because Internet Explorer will not play it.
My proposed solution is to do a real-time conversion from the source format to mp3.
I've cobbled together a partially working solution from various other questions here and in the NAudio forums, but it throws an exception as noted in the comments below:
private void NAudioTest(string url)
{
Stream outStream = new MemoryStream();
var format = WaveFormat.CreateMuLawFormat(8000, 1);
using (Stream ms = new MemoryStream())
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
using (Stream stream = request.GetResponse().GetResponseStream())
{
using (var reader = new RawSourceWaveStream(stream, format))
{
// reader is not seekable; we need to convert to a byte array to seek
var bytes = reader.ToByteArray();
// create a new stream from the byte aray
var seekableStream = new MemoryStream(bytes);
// instantiating a WaveFileReader as follows will throw an exception:
// "System.FormatException: Not a WAVE file - no RIFF header"
using (var waveReader = new WaveFileReader(seekableStream))
{
using (var pcmStream = WaveFormatConversionStream.CreatePcmStream(waveReader))
{
var pcmBytes = pcmStream.ToByteArray();
var mp3 = pcmBytes.ToMp3();
}
}
}
}
}
}
public static class StreamExtensions
{
public static byte[] ToByteArray(this Stream stream)
{
var ms = new MemoryStream();
var buffer = new byte[1024];
int bytes = 0;
while ((bytes = stream.Read(buffer, 0, buffer.Length)) > 0)
ms.Write(buffer, 0, bytes);
return ms.ToArray();
}
}
public static class ByteExtensions
{
public static byte[] ToMp3(this byte[] bytes)
{
using (var outStream = new MemoryStream())
{
using (var ms = new MemoryStream(bytes))
{
using (var reader = new WaveFileReader(ms))
{
using (var writer = new LameMP3FileWriter(outStream, reader.WaveFormat, 64))
{
reader.CopyTo(writer);
return outStream.ToArray();
}
}
}
}
}
}
I've been poking around at this for most of the day and I feel like I'm introducing unnecessary complexity into something that seems like it should be fairly straightforward.
Any help would be much appreciated.
Note: I cannot change the source format and supporting IE is a requirement.
EDIT: I resolved the RIFF exception and am able to produce a stream of the MP3, but it's nothing but white noise. Hopefully I can resolve that as well. My new code is as follows:
[HttpGet]
public ActionResult GetMp3(string url)
{
if (String.IsNullOrWhiteSpace(url))
return null;
var muLawFormat = WaveFormat.CreateMuLawFormat(8000, 1);
var compressedStream = new MemoryStream();
using (var ms = new MemoryStream())
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
using (Stream webStream = request.GetResponse().GetResponseStream())
{
var buffer = new byte[4096];
int read;
while (webStream != null && (read = webStream.Read(buffer, 0, buffer.Length)) > 0)
ms.Write(buffer, 0, read);
}
ms.Position = 0;
using (WaveStream wav = WaveFormatConversionStream.CreatePcmStream(new RawSourceWaveStream(ms, muLawFormat)))
using (var mp3 = new LameMP3FileWriter(compressedStream, new WaveFormat(), LAMEPreset.MEDIUM_FAST))
wav.CopyTo(mp3);
}
compressedStream.Seek(0, 0);
return new FileStreamResult(compressedStream, "audio/mpeg");
}
This works for me (and I needed to do exactly what you wanted to do). Hope this helps someone else as well. I used NAudio with LAME.
You have to make sure that you copy the libmp3lamexx.dll files to your webserver's BIN location or to some folder in the %PATH% variable, else it won't work.
string sq = /* URL of WAV file (http://foo.com/blah.wav) */
Response.ContentType = "audio/mpeg";
using (WebClient wc = new WebClient())
{
if (!sq.ToLower().EndsWith(".wav"))
{
byte[] rawFile = wc.DownloadData(sq.Trim());
Response.OutputStream.Write(rawFile, 0, rawFile.Length);
}
else
{
using (var wavReader = new WaveFileReader(new MemoryStream(wc.DownloadData(sq.Trim()))))
{
try
{
using (var wavWriter = new LameMP3FileWriter(Response.OutputStream, wavReader.WaveFormat, LAMEPreset.ABR_128))
{
wavReader.CopyTo(wavWriter);
}
}
catch (ArgumentException)
{
var newFormat = new WaveFormat(wavReader.WaveFormat.SampleRate, 16, 2);
using (var pcmStream = new WaveFormatConversionStream(newFormat, wavReader))
{
using (var wavWriter = new LameMP3FileWriter(Response.OutputStream, pcmStream.WaveFormat, LAMEPreset.ABR_128))
{
pcmStream.CopyTo(wavWriter);
}
}
}
}
}
Response.Flush();
Response.End();
}