How to create WriteableBitmap from BitmapImage? - c#-4.0

I could create WriteableBitmap from pictures in Assets.
Uri imageUri1 = new Uri("ms-appx:///Assets/sample1.jpg");
WriteableBitmap writeableBmp = await new WriteableBitmap(1, 1).FromContent(imageUri1);
but, I can't create WriteableBitmap from Pictures Directory,(I'm using WinRT XAML Toolkit)
//open image
StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
StorageFile file = await picturesFolder.GetFileAsync("sample2.jpg");
var stream = await file.OpenReadAsync();
//create bitmap
BitmapImage bitmap2 = new BitmapImage();
bitmap2.SetSource();
bitmap2.SetSource(stream);
//create WriteableBitmap, but cannot
WriteableBitmap writeableBmp3 =
await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(bitmap2);
Is this correct ?

This is a total contrivance, but it does seem to work ...
// load a jpeg, be sure to have the Pictures Library capability in your manifest
var folder = KnownFolders.PicturesLibrary;
var file = await folder.GetFileAsync("test.jpg");
var data = await FileIO.ReadBufferAsync(file);
// create a stream from the file
var ms = new InMemoryRandomAccessStream();
var dw = new Windows.Storage.Streams.DataWriter(ms);
dw.WriteBuffer(data);
await dw.StoreAsync();
ms.Seek(0);
// find out how big the image is, don't need this if you already know
var bm = new BitmapImage();
await bm.SetSourceAsync(ms);
// create a writable bitmap of the right size
var wb = new WriteableBitmap(bm.PixelWidth, bm.PixelHeight);
ms.Seek(0);
// load the writable bitpamp from the stream
await wb.SetSourceAsync(ms);

Here's the way reading an image to a WriteableBitmap works as Filip noted:
StorageFile imageFile = ...
WriteableBitmap writeableBitmap = null;
using (IRandomAccessStream imageStream = await imageFile.OpenReadAsync())
{
BitmapDecoder bitmapDecoder = await BitmapDecoder.CreateAsync(
imageStream);
BitmapTransform dummyTransform = new BitmapTransform();
PixelDataProvider pixelDataProvider =
await bitmapDecoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied, dummyTransform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.ColorManageToSRgb);
byte[] pixelData = pixelDataProvider.DetachPixelData();
writeableBitmap = new WriteableBitmap(
(int)bitmapDecoder.OrientedPixelWidth,
(int)bitmapDecoder.OrientedPixelHeight);
using (Stream pixelStream = writeableBitmap.PixelBuffer.AsStream())
{
await pixelStream.WriteAsync(pixelData, 0, pixelData.Length);
}
}
Note that I am using the pixel format and alpha mode Writeable Bitmap uses and that I pass .

WriteableBitmapFromBitmapImageExtension.FromBitmapImage() works by using the original Uri used to load BitmapImage and IIRC it only works with BitmapImages from the appx. In your case there isn't even a Uri since loading from Pictures folder can only be done by loading from stream, so your options from the fastest to slowest (I think) are:
Open the image as WriteableBitmap from the get go, so that you don't need to reopen it or copy bits around.
If you need to have two copies - open it as WriteableBitmap and then create a new WriteableBitmap of same size and copy the pixel buffer.
If you need to have two copies - track the path used to open the first bitmap and then create a new WriteableBitmap by loading it from the same file as the original one.
I think option 2 might be faster than option 3 since you avoid decoding a compressed image twice.

Related

chrome extension : how to fill input[type=file]? [duplicate]

How to append blob to input of type file?
<!-- Input of type file -->
<input type="file" name="uploadedFile" id="uploadedFile" accept="image/*"><br>
// I am getting image from webcam and converting it to a blob
function takepicture() {
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(video, 0, 1, width, height);
var data = canvas.toDataURL('image/png');
var dataURL = canvas.toDataURL();
var blob = dataURItoBlob(dataURL);
photo.setAttribute('src', data);
}
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
// How can I append this var blob to "uploadedFile". I want to add this on form submit
It is possible to set value of <input type="file">.
To do this you create File object from blob and new DataTransfer object:
let file = new File([data], "img.jpg",{type:"image/jpeg", lastModified:new Date().getTime()});
let container = new DataTransfer();
Then you add file to container thus populating its 'files' property, which can be assigned to 'files' property of file input:
container.items.add(file);
fileInputElement.files = container.files;
Here is a fiddle with output, showing that file is correctly placed into input.
The file is also passed correctly to server on form submit. This works at least on Chrome 88.
If you need to pass multiple files to input you can just call container.items.add multiple times. So you can add files to input by keeping track of them separately and overwriting its 'files' property as long as this input contains only generated files (meaning not selected by user). This can be useful for image preprocessing, generating complex files from several simple ones (e.g. pdf from several images), etc.
API references:
File object
DataTransfer object
I had a similar problem with a fairly complex form in an angular app, so instead of the form I just sent the blob individually using XMLHttpRequest(). This particular "blob" was created in a WebAudioAPI context, creating an audio track in the user's browser.
var xhr = new XMLHttpRequest();
xhr.open('POST', 'someURLForTheUpload', true); //my url had the ID of the item that the blob corresponded to
xhr.responseType = 'Blob';
xhr.setRequestHeader("x-csrf-token",csrf); //if you are doing CSRF stuff
xhr.onload = function(e) { /*irrelevant code*/ };
xhr.send(blob);
You can't change the file input but you can use a hidden input to pass data. ex.:
var hidden_elem = document.getElementById("hidden");
hidden_elem.value = blob;
I had take too much time to find how to do "url, blob to input -> preview"
so I had do a example you can check here
https://stackoverflow.com/a/70485949/6443916
https://vulieumang.github.io/vuhocjs/file2input-input2file/
image bonus

NodeJS: Updating Exif data and saving image using PIEXIF

I need to update orientation tag(EXIF data) for the uploaded image. I am using "PIEXIF" for this. I am not using express but swagger. The code I've written is:
//Get the uploaded buffer
var _originalBuffer = req.swagger.params.uploadedFile.value.buffer;
let Duplex = require('stream').Duplex;
//Create stream from buffer. This stream is required later to send to cloud.
let _uploadedFileStream = new Duplex();
_uploadedFileStream.push(_originalBuffer);
_uploadedFileStream.push(null);
//Create base 64 string so that "PIEXIF" can read exif data from it.
const jpegData = "data:image/jpeg;base64, " + createStringFromBuffer(_originalBuffer, 'base64');
//Read exif data.
var _exifData = piexif.load(jpegData);
//Create a copy of exif data. Will be used to create a new image with updated orientation tag.
var _exifDataCopied = {};
for (var key in _exifData) {
_exifDataCopied[key] = _exifData[key];
}
//Update orientation tag.
if (_exifDataCopied["0th"][piexif.ImageIFD.Orientation])
_exifDataCopied["0th"][piexif.ImageIFD.Orientation] = 1;
//Example taken from https://www.npmjs.com/package/piexifjs
//From here onwards, there seems to be an issue.
var exifbytes = piexif.dump(_exifDataCopied);
var newData = piexif.insert(exifbytes, createStringFromBuffer(_originalBuffer, 'binary'));
var newJpeg = new Buffer(newData);
//Create a new stream and save it as image back.
let _updatedFileStream = new Duplex();
_updatedFileStream.push(newJpeg);
_updatedFileStream.push(null);
var fs = require('fs');
var writeStream = fs.createWriteStream("./uploads/" + "Whatever.jpg")
The issue is there is no error thrown by the code. The image is also getting saved in the directory but it is corrupted. I can not preview it. Since, the code does not breaks anywhere, I am confused what could be the issue? The function to convert buffer to string with different encoding(since I need it a lot) is:
var createStringFromBuffer = function(_buffer, _encoding) {
return Buffer.from(_buffer).toString(_encoding);
}
Can someone point out where I am mistaking? I am using the example given Here

UWP - ImageBrush full path to ImageSource

I have an ellipse and I want to fill it with image. And I would like to set full path to the image to ImageSource property of ImageBrush. But I wasn't able to accomplish it.
I've tried to add:
C:/Users/someuser/Pictures/untitled.png
C:\\Users\\someuser\\Pictures\\untitled.png which came from FilePicker
C:\Users\misko\Pictures\untitled.png.
But non of this works. Can you please explain to me how to properly set full path?
You have to open the file first using FilePicker
if (file != null)
{
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bitmapImage.SetSourceAsync(stream);
var decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
grid.Background = new ImageBrush
{
ImageSource = bitmapImage
};
}

converting Image raw data to bitmapimage in windows universal app

I am trying to implement a windows universal application. I am facing one issue for converting the image raw data(byte array) to the BitmapImage control. I don't know the type of the image raw data. I used the below code,
private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
{
var bitmapImage = new BitmapImage();
var stream = new InMemoryRandomAccessStream();
await stream.WriteAsync(byteArray.AsBuffer());
stream.Seek(0);
bitmapImage.SetSource(stream);
return bitmapImage;
}
Image is not displayed in window. When I debugging , found that height & width of bitmapImage object is 0.
if anybody know the solution for this, please help me
Finally my issue solved , when I used the below code,
var bmp = new WriteableBitmap(320, 240);
using (var stream = bmp.PixelBuffer.AsStream())
{
stream.Write(bytes, 0, bytes.Length);
myImage.Source = bmp;
}
I'm using the same code and in works for me but I create BitmapImage and set its source on dispatcher's thread - maybe that's the key to your problem.

MobileService table store picture

I want to save an image to my Azure MobileService.
I have been looking around and found that you can use blob and azure storage. But instead of implementing this I would love if you could convert an image to string or stream that could be stored in a normal azure mobile service table.
I am creating images in my app as :
Canvas found = null;
try
{
found = FindParentOfType<Canvas>(ViewInteractionCanvas.canvas);
}
catch (Exception)
{
//MessageBox.Show(e.Message.ToString(), "ERROR", MessageBoxButton.OK);
found = ViewInteractionCanvas.canvas;
}
WriteableBitmap writeableBitmap = new WriteableBitmap(found, null);
var imageBrush = new ImageBrush
{
ImageSource = writeableBitmap,
Stretch = Stretch.None
};
writeableBitmap = null;
GC.Collect();
try
{
FindChildCanvas(found, imageBrush);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString(), AppResources.ErrorSaving, MessageBoxButton.OK);
return false;
}
var fileStream = new MemoryStream();
writeableBitmap = new WriteableBitmap(found, null);
writeableBitmap.SaveJpeg(fileStream, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 100, 100);
fileStream.Seek(0, SeekOrigin.Begin);
string tempJPEG = "My.jpg";
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream IsofileStream = myIsolatedStorage.CreateFile(tempJPEG);
/*
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
*/
// Encode WriteableBitmap object to a JPEG stream.
//Extensions.SaveJpeg(wb, IsofileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
writeableBitmap.SaveJpeg(IsofileStream, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 100, 100);
IsofileStream.Close();
}
dialogResult = MessageBox.Show(AppResources.ShieldCreator_SaveShield, AppResources.ShieldCreator_SaveShieldTitle, MessageBoxButton.OKCancel);
if (dialogResult == MessageBoxResult.OK)
{
MediaLibrary library = new MediaLibrary();
library.SavePictureToCameraRoll("picture", fileStream);
}
if (dialogResult == MessageBoxResult.Cancel)
{
}
fileStream.Close();
I was thinking that I could send the filestream or something like that? But Have not succeeded in doing so. Maybe this is completely impossible. But just wanted to investigate the possibility instead of starting to learn a new concept.
Hope somebody can help.
By default, Mobile Services data is backed by SQL Database. As long as you can find a way to create a proper data type in your table, you'd be able to do this. Just keep in mind: SQL Database databases are limited to 150GB, which will be eaten up faster if storing content in the database instance vs, say, blob storage with a URL to that blob being stored in your SQL table (which also costs significantly less than SQL Database service).
What you're talking about doing (storing the image data in your SQL database) is possible and not altogether difficult, but definitely not recommended. There are several issues including the size of the data and the inefficiency of storing data like this. At the end of the day though, if that's how you want to implement it, I have posts explaining how you can do so from an Android and an iOS app.:
Android: http://chrisrisner.com/Storing-Images-from-Android-in-Windows-Azure-Mobile-Services
iOS: http://chrisrisner.com/Storing-Images-from-iOS-in-Windows-Azure-Mobile-Services
Due to the data types supported by Mobile Services, you'd need to store the image data as strings (varchars in the database). Again, far from the most efficient but it'll work.

Resources