Tuesday, July 11, 2017

Mobile Cross Platform Image manipulation with Xamarin (Android / iOS / Windows UWP)

There are some common image functions I tend to need a lot with mobile apps.
These are:
  1. Resizing images – usually with a specific size in mind
  2. Knowing what size and existing image is
  3. Converting an image between png and jpeg formats
I recently particularly needed these kinds of functions for including images in pdf documents (more on cross platform pdf generation here)
All the source code for the above can be found here, and the nuget package is available here.
All the code assumes images are in byte[] format – what you’d normally use for storing images in database repos etc.
As an aside – there’s a separate Xamarin Forms Value Converter nuget for binding a byte[] image to an ImageSource here
For all the code, you can choose to use the command interface, or the ImageTools interface, which wraps the functionality in explicit method calls.
     image

Resizing an Image

This is the most common requirement for image manipulation.
Images taken from disc, or using the camera are usually way to big to be included for wire transfers or light weight repo stores. Other usages are perhaps generating a pre-defined size thumbnail image.
IResizeImageCommand resizeCommand = DependencyService.Get<IResizeImageCommand>();  
ResizeImageContext context = new ResizeImageContext  { Height = 130, Width = 130, OriginalImage = image  };  
var resizeResult = await resizeCommand.ExecuteAsync(context);  
if (resizeResult.IsValid())  
{  
   image = resizeResult.ResizedImage;  
}  

Analyze an Image

Sometimes you just want to know what the dimensions of an image is, or what size it is, or in what orientation:
 var analyseImage = DependencyService.Get<IAnalyseImageCommand>();
var analyseResult = await analyseImage.ExecuteAsync(new AnalyseImageContext { Image = imageAsBytes });
if (analyseResult.IsValid())
{
   var imageWidth = analyseResult.Width.ToString();
   var imageHeight = analyseResult.Height.ToString();
   var orientation = analyseResult.Orientaion.ToString();
   var size = analyseResult.SizeInKB.ToString();
}

Convert an Image (Png and Jpeg support only)

I needed this recently because the pdf library I was using only supported jpeg files.
var imageTools = DependencyService.Get<IImageTools>();

var convertResult = await imageTools.ConvertImageAsync(new ConvertImageContext(Logo, ImageFormat.Jpeg));
if (convertResult.TaskResult == TaskResult.Success)
{
   ConvertedLogo = convertResult.ConvertedImage;
   ConvertedSize = ConvertedLogo.SizeInKB().ToString();
}
Here I’m using the ImageTools dependency – you could just as easily have used the command as in the first two examples.
…. I haven’t tested all the platforms extensively, so if you find a bug, feel free to log an issue on github, or better yet: a pull request with the fix.

Thursday, July 6, 2017

Generate pdf documents for iOS, Android & Windows UWP using Xamarin Forms and Syncfusion Essentials–Part 2

Part 1 of the post can be found here
There I talk about getting started, and generating a simple pdf invoice.

The updated source code is in the same repository here
Code of interest is in the GenerateInvoiceCommand, the PdfGenerator & PdfExtensions

Today, I’m going to be talking about generating line items for the invoice. Here’s a screenshot of the generated result on all three platforms:
image
    
With Syncfusion Essentials Pdf, there are two main options for this: PdfLightTable & PdfGrid

After having implemented both, I don’t really see why both exist – the effort and functionality is about the same for both options.
I can say though, that PdfGrid definitely seems the more stable of the two – I found a few bugs in PdfLightTable along the way.

A look at the result: PdfLightTable on the left, and PdfGrid on the right

imageimage

Some things to consider (included in the sample code above)

More documentation on pdf grid and light table can be found here

Adding data

Both types used direct data-source methodologies.

Grid:
image

LightTable:
image

Sizing columns to content

Unfortunately this isn’t as simple as it should be. Static widths are easy – content not so much.
I created extensions for both LightTable and PdfGrid here (currently LightTable doesn’t appear to work)
Currently we have to cycle through all the column data, and measure which is the longest text, and then set the width to the max content width, hence the need for data, page width and font used.

image

Styling the table

PdfGrid has some built-in styles, as well as customization
image

LightTable you can customize the same as with PdfGrid – I created an extension to apply the most common properties to mimic the built-in style of the PdfGrid
image

Paginating the data

This applies to both table types, although again, LightTable seems to have some trouble honoring the PageinateBounds property – which is needed to the table doesn’t render over any footer data.
image

Drawing the pdf document

image

simple enough.

There’s tons more functionality in syncfusion’s pdf library – go check it out.

Clone the repo and play around with the code - and log an issue if you find any bugs in there :)

And don’t forget syncfusion’s awesome community license that  offers their controls free for indie hackers and small businesses.