Convert 24bit image to 8bit in monotouch? - c#

We have an image processing windows application where we are using lead tools for converting and images from 24/48 bit images to 8 bit images.
As an experiment I'm porting the application to iPad using MonoTouch and C#, now the LeadTools components are incompatible with Monotouch. Is there any alternate I can use? if not how can I convert 24/48 bit images to 8 bit?

To use Apple's imaging tools here is where I would start:
Convert your raw bytes into a pixel format supported by the platform. See the Quartz 2D documentation on supported pixel formats.
Note that iOS doesn't currently have a 24 or 48 bit format. However, if your 24 bit format is 8 bits per channel (RGB) you could add 8 bits of ignored alpha. (Alpha options are in MonoTouch.CoreGraphics.CGImageAlphaInfo)
Convert your raw bytes into a CGImage. Here is an example of how to do that
var provider = new CGDataProvider(bytes, 0, bytes.Length);
int bitsPerComponent = 8;
int components = 4;
int height = bytes.Length / components / width;
int bitsPerPixel = components * bitsPerComponent;
int bytesPerRow = components * width; // Tip: When you create a bitmap graphics context, you’ll get the best performance if you make sure the data and bytesPerRow are 16-byte aligned.
bool shouldInterpolate = false;
var colorSpace = CGColorSpace.CreateDeviceRGB();
var cgImage = new CGImage(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow,
colorSpace, CGImageAlphaInfo.Last, provider,
null, shouldInterpolate, CGColorRenderingIntent.Default);
Use a Core Image Filter to convert to Monochrome
var mono = new CIColorMonochrome
{
Color = CIColor.FromRgb(1, 1, 1),
Intensity = 1.0f,
Image = CIImage.FromCGImage(image)
};
CIImage output = mono.OutputImage;
var context = CIContext.FromOptions(null);
var renderedImage = context.CreateCGImage(output, output.Extent);
Finally you can retrieve the raw bytes of that image by drawing into a CGBitmapContext constructed according to your desired parameters.
I suspect this pipeline could be optimized, but it is a place to start. I'd be interested to hear what you end up with.

I think your best option will be to do native calls to the LeadTools libraries - any image manipulation in C# that I can think of is going to rely on components like GDI+ and the System.Drawing namespace which isn't supported by monotouch.
You can call native objective-C code from your monotouch project by creating a Binding project - http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types
This should allow you to port your code in a way that will produce the exact same image/quality/format without really having to rework your current conversion code.

Related

System.Drawing.Common.Bitmap cross platform alternatives

I am looking to convert PDF files into images. Docnet is able to convert the pdf into bytes[] and their samples show how to save this byte[] into an image file using Bitmap. Documentation
However, the solution won't work on linux machine since Bitmap requires few libraries pre-installed on the system.
I've tried ImageSharp to convert the byte[] using SixLabors.ImageSharp.Image.Load<Bgra32>(rawBytes), however, it throws Unhandled exception. SixLabors.ImageSharp.InvalidImageContentException: PNG Image does not contain a data chunk.
Does anyone knows any alternative to achieve this.
PS - I'm open to explore any other cross platform FREE supported alternatives to convert PDF files to images.
This works fine with ImageSharp assuming Docnet works then ImageSharp will work fine for you.
The trick is you want to be using the Image.LoadPixelData<Bgra32>(rawBytes, width, height); API not the Image.Load<Bgra32>(encodedBytes); one.
using Docnet.Core;
using Docnet.Core.Models;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using var docReader = DocLib.Instance.GetDocReader(
"wikipedia_0.pdf",
new PageDimensions(1080, 1920));
using var pageReader = docReader.GetPageReader(0);
var rawBytes = pageReader.GetImage();
var width = pageReader.GetPageWidth();
var height = pageReader.GetPageHeight();
// this is the important line, here you are taking a byte array that
// represents the pixels directly where as Image.Load<Bgra32>()
// is expected an encoded image in png, jpeg etc format
using var img = Image.LoadPixelData<Bgra32>(rawBytes, width, height);
// you are likely going to want this as well otherwise you might end up with transparent parts.
img.Mutate(x => x.BackgroundColor(Color.White));
img.Save("wikipedia_0.png");

How to render video from ARGB Frames

I'm using the Microsoft.MixedReality.WebRTC library and I am planing on using it for my next project - a Real-Time video chatting app.
I have been able to establish a connection and pass video frames around.
How would I properly render those Frames and display them as Video?
Using WPF's MediaElement seems pretty easy, but I can only input an Uri object as source, I cannot feed it single frames, AFAIK.
I have read that drawing Bitmaps is a possible solution, but I am sure this would mean many hours reinventing the wheel and testing, which I am not a fan of doing, unless there is no other way.
The library works as follows:
Each time a new frame is received by the client the Argb32VideoFrameReady event is raised. A Argb32VideoFrame struct object is then passed to the callback, which contains an IntPtr to the raw data. Height, Width and Stride are also provided.
More Information on the specific struct here
What would be some ways I could achieve this?
I am planning on using WPF.
The solution should target Windows 7+ and .Net Framework 4.6.2.
Thanks in advance.
With an Image element in XAML
<Image x:Name="image"/>
the simple method below would directly copy the frame into a WriteableBitmap that is assigned to the Image's Source property.
private void UpdateImage(Argb32VideoFrame frame)
{
var bitmap = image.Source as WriteableBitmap;
var width = (int)frame.width;
var height = (int)frame.height;
if (bitmap == null ||
bitmap.PixelWidth != width ||
bitmap.PixelHeight != height)
{
bitmap = new WriteableBitmap(
width, height, 96, 96, PixelFormats.Bgra32, null);
image.Source = bitmap;
}
bitmap.WritePixels(
new Int32Rect(0, 0, width, height),
frame.data, height * frame.stride, frame.stride);
}
ARGBVideoFrame from here: https://github.com/microsoft/MixedReality-WebRTC/blob/master/libs/Microsoft.MixedReality.WebRTC/VideoFrame.cs
PixelFormats.Bgra32 seems to be the proper format, due to this comment on the struct:
The ARGB components are in the order of a little endian 32-bit integer, so 0xAARRGGBB, or (B, G, R, A) as a sequence of bytes in memory with B first and A last.

Displaying Thumbnails of very high resolution images Fast with Minimal Delay

I need to show the preview thumbnails of high resolution images in a control for user selection. I currently use ImageListView to load images.
This works fine for low to medium resolution images.But when it comes to showing thumbnails of very high resolution images there is a noticeable delay.Sample image can be downloaded from https://drive.google.com/open?id=1Qgu_aVXBiMlbHluJFU4fBvmFC45-E81C
The image size is around 5000x3000 pixels and size is around 12 MB.The issue can be replicated by using 1000 copies of this image.
The issue screen capture is uploaded here
https://giphy.com/gifs/ZEH3T3JTfN42OL3J1A
The images are loaded using a background worker
foreach (var f in filepaths)
{
imageListView1.Items.Add(f);
}
1. In order to solve this issue I tried resizing large resolution images and adding the resized image to ImageListView ... but for resizing there is a heavy time consumption and thumbnail generation is slow.
Bitmap x = UpdatedResizeImage2(new Bitmap(f), new Size(1000, 1000));
string q = Path.GetTempPath() + Path.GetFileName(f);
x.Save(Path.GetTempPath() + Path.GetFileName(f));
x.Dispose();
imageListView1.Items.Add(Path.GetTempPath() + Path.GetFileName(f));
2. I have also tried Image.CreateThumbnail Method but this is also quite slow.
Is there a better way to solve this issue?
I would suggest using image processing library such ImageMagick.
ImageMagick has optimized this feature and you have Magick.NET a nuget package for .NET.
It is simple and straight forward:
var file = new FileInfo(#"c:\temp\input.jpg");
using (MagickImage image = new MagickImage(file))
{
{
image.Thumbnail(new MagickGeometry(100, 100));
image.Write(#"C:\temp\thumbnail.jpg");
}
}
example I made:
Here is some documentation and references that might be useful:
https://imagemagick.org/Usage/thumbnails/#creation
http://www.imagemagick.org/Usage/thumbnails/
https://github.com/dlemstra/Magick.NET
https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
https://devblogs.microsoft.com/dotnet/net-core-image-processing/
https://weblogs.asp.net/bleroy/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi
Alternatives to System.Drawing for use with ASP.NET?
You could use WPF interop and use the DecodePixelWidth/Height properties. They use underlying Windows imaging layer technology ("Windows Imaging Component") to create an optimized thumbnail, saving lots of memory (and possibly CPU): How to: Use a BitmapImage (XAML)
You can also use WPF/WIC by code, with a code like this (adapted from this article The fastest way to resize images from ASP.NET. And it’s (more) supported-ish.. You just need to add a reference to PresentationCore and WindowsBase which shouldn't be an issue for a desktop app.
// needs System.Windows.Media & System.Windows.Media.Imaging (PresentationCore & WindowsBase)
public static void SaveThumbnail(string absoluteFilePath, int thumbnailSize)
{
if (absoluteFilePath == null)
throw new ArgumentNullException(absoluteFilePath);
var bitmap = BitmapDecoder.Create(new Uri(absoluteFilePath), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];
int width;
int height;
if (bitmap.Width > bitmap.Height)
{
width = thumbnailSize;
height = (int)(bitmap.Height * thumbnailSize / bitmap.Width);
}
else
{
width = (int)(bitmap.Width * thumbnailSize / bitmap.Height);
height = thumbnailSize;
}
var resized = BitmapFrame.Create(new TransformedBitmap(bitmap, new ScaleTransform(width / bitmap.Width * 96 / bitmap.DpiX, height / bitmap.Height * 96 / bitmap.DpiY, 0, 0)));
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(resized);
var thumbnailFilePath = Path.ChangeExtension(absoluteFilePath, thumbnailSize + Path.GetExtension(absoluteFilePath));
using (var stream = File.OpenWrite(thumbnailFilePath))
{
encoder.Save(stream);
}
}
Otherwise there are lots of tools out there like MagicScaler, FreeImage ImageSharp, ImageMagick, Imazen, etc. Most were written for ASP.NET/Web server scenarios (for which WPF is officially not supported but works, read the article) and are also cross-platform which you don't seem to need. I'm not sure they're generally faster or use less memory than builtin Windows technology, but you should test all this in your context.
PS: otherwise there's no magic bullet, bigger images take more time.
There's also NetVips, the C# binding for libvips.
It's quite a bit quicker than Magick.NET: between 3x and 10x faster, depending on the benchmark.
Thumbnailing is straightforward:
using NetVips;
var image = Image.Thumbnail("some-image.jpg", 128);
image.WriteToFile("x.jpg");
There's an introduction in the documentation.
Most of answers approach is to resize bitmap and then save it. Its a bit offcourse slow, specially if you say very high resolution.
Why not use existing thumbnail created by windows explorer ? This is fastest way of all (specially if you use smaller thumbnails).
//https://stackoverflow.com/a/1751610
using Microsoft.WindowsAPICodePack.Shell;
var shellFile = ShellFile.FromFilePath(pathToYourFile); Bitmap
Image image = shellFile.Thumbnail.LargeBitmap;
Nuget : https://www.nuget.org/packages/WindowsAPICodePack-Shell (around 600KB)
Note: Its same as others, if thumbnail arent cached already.

How to find barcodes of a PDF document

I started searching how to create a Windows Phone 8 app to recognize barcodes inside a PDF document.
My best guest is to following the process below:
Find a lib to split PDF documents into image streams (one per page).
Find a lib to recognize if there is a barcode in the image stream:
2.1. Try to recognize barcode in each portion of the image, i. e.:
try #1 (from y = 0, x = 0 to y = 100, x = 100);
try #2 (from y = 100, x = 0 to y = 200, x = 100);
try #3 (from y = 200, x = 0 to y = 300, x = 100);
and so on.
I'm wondering if this is the best approach to accomplish barcode recognition in a PDF document using WP8.
Another concern is about whether this process when executed by a not so good device will present an acceptable performance.
Someone already did that? Any advice?
UPDATE
I want to scan ITF barcodes, i. e., I need to scan the barcode in this image:
I'm trying to start achieving the scanning barcodes from a Image, but I'm not getting success. Below is my first try:
//get the assets folder for the app
StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
BitmapSource bitmapSource = await GetBitmapImage(folder, "Barcode.png");
WriteableBitmap writeableBitmap = new WriteableBitmap(bitmapSource);
var rgb = new RGBLuminanceSource(writeableBitmap.ToByteArray(), writeableBitmap.PixelWidth, writeableBitmap.PixelHeight);
var hybrid = new HybridBinarizer(rgb);
BinaryBitmap binBitmap = new BinaryBitmap(hybrid);
Reader reader = new ITFReader();
try
{
Result result = reader.decode(binBitmap);
if (result != null)
{
this.textBlock.Text = result.Text;
}
}
catch (Exception ex)
{
this.textBlock.Text = ex.Message;
}
Unfortunately, my text box is being filled up with this Exception:
Exception of type 'com.google.zxing.ReaderException' was thrown.
I'm using this "lib": https://silverlightzxing.codeplex.com/
Yes, this concept actually works.
Read the PDF as Image
after that use any external Library to detect Barcodes from image. (There are many libraries available to do so)
And for another concern that you mentioned regarding performance of Low-End devices, it depends on many things.
First of all it depends on the library that you use to convert PDF to Image
then library that you use to detect Barcode from Image.
though there is no certainity for Time Complexity in this Task, what i think is it will not take much time then required..! It's a general process, so you can go with the scenario above.
Hope that helps...
I'd like to help you to implement the part 1 of the solution, render PDF to image:
this blog post shows how to do it on windows phone and this lib can be used to convert PDFs to images in universal windows store apps as well as xamarin apps. I personally use it in my projects and because it offers same API for all platforms it fits incredibly well.

Instagram Photo Effects in Windows 8 metro apps using c#

I need to implement Instagram photo effects like amaro, hudson, sepia, rise, and so on. I know this article only use basic effects: http://code.msdn.microsoft.com/windowsdesktop/Metro-Style-lightweight-24589f50
Another way suggested by people are to implement Direct2d and then apply using that. But for that I would need to write C++ code, where I have zero experience.
Can anyone suggest some other way to implement Instagram effects in c#?
Is there any built in c++ file for these effects?
Please see this example from CodeProject : Metro Style Lightweight Image Processing
The above example contains these image effects.
Negative
Color filter
Emboss
SunLight
Black & White
Brightness
Oilpaint
Tint
Please note above example seems to be implemented on either developer preview or release preview of Windows 8. So you will get error like this
'Windows.UI.Xaml.Media.Imaging.WriteableBitmap' does not contain a
constructor that takes 1 arguments
So you have to create instance of WriteableBitmap by passing pixel height and pixel width of image. I have edited the sample and it is working for me. You have to change wb = new WriteableBitmap(bs); to wb = await GetWB();
StorageFile originalImageFile;
WriteableBitmap cropBmp;
public async Task<WriteableBitmap> GetWB()
{
if (originalImageFile != null)
{
//originalImageFile is the image either loaded from file or captured image.
using (IRandomAccessStream stream = await originalImageFile.OpenReadAsync())
{
BitmapImage bmp = new BitmapImage();
bmp.SetSource(stream);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
byte[] pixels = await GetPixelData(decoder, Convert.ToUInt32(bmp.PixelWidth), Convert.ToUInt32(bmp.PixelHeight));
cropBmp = new WriteableBitmap(bmp.PixelWidth, bmp.PixelHeight);
Stream pixStream = cropBmp.PixelBuffer.AsStream();
pixStream.Write(pixels, 0, (int)(bmp.PixelWidth * bmp.PixelHeight * 4));
}
}
return cropBmp;
}
Let me know if you are facing any problem.

Categories

Resources