问题
I found this documentation for exporting and saving a Canvas as a png. It gives the following code:
var Imaging = Windows.Graphics.Imaging;
var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
picker.fileTypeChoices.insert("PNG file", [".png"]);
var imgData, fileStream = null;
picker.pickSaveFileAsync().then(function (file) {
if (file) {
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
} else {
return WinJS.Promise.wrapError("No file selected");
}
}).then(function (stream) {
fileStream = stream;
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream);
}).then(function (encoder) {
//Set the pixel data--assume "encoding" object has options from elsewhere
encoder.setPixelData(encoding.pixelFormat, encoding.alphaMode,
encoding.width, encoding.height, encoding.dpiX, encoding.dpiY,
new Uint8Array(imgData.data));
//Go do the encoding
return encoder.flushAsync();
}).done(function () {
//Make sure to do this at the end
fileStream.close();
}, function () {
//Empty error handler (do nothing if the user canceled the picker
});
In the 'encoder.setPixelData' area, they use an object called 'encoding' to set all the values, but have no explanation of how this object is created in any of the prior steps.
How can I create this 'encoding' object to complete the example?
回答1:
I found a different way to save the canvas, still didn't solve my initial problem
I can turn the canvas into a blob stream and save that to a png file
function saveCanvasAsImage(canvasElement) {
var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
picker.fileTypeChoices.insert("PNG file", [".png"]);
var input, output = null;
var blob = canvasElement.msToBlob();
return picker.pickSaveFileAsync()
.then(function (file) {
if (file) {
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
} else {
return WinJS.Promise.wrapError("No file selected");
}
})
.then(function (op) {
output = op;
input = blob.msDetachStream();
return Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output);
})
.then(function() {
return output.flushAsync();
})
.done(function() {
input.close();
output.close();
}, function(e) {
// handle error here
});
}
Unfortunately it's saving with a transparent background, but maybe there's a way I can make my canvas have a white background.
[edit] ----
So I found a way to answer my original question more directly:
function saveCanvasAsImage(canvasElement) {
var Imaging = Windows.Graphics.Imaging;
var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
// picker.fileTypeChoices.insert("JPEG file", [".jpg"]);
picker.fileTypeChoices.insert("PNG file", [".png"]);
var fileStream, decoder, encoding, pixels = null;
var encoderIds = {
'.png': Imaging.BitmapEncoder.pngEncoderId,
'.jpg': Imaging.BitmapEncoder.jpegEncoderId
}
var encoderId = encoderIds['.jpg'];
var blob = canvasElement.msToBlob();
return Imaging.BitmapDecoder.createAsync(Imaging.BitmapDecoder.pngDecoderId,
blob.msDetachStream())
.then(function (dc) {
decoder = dc;
return picker.pickSaveFileAsync();
}).then(function (file) {
if (file) {
encoderId = encoderIds[file.fileType];
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
} else {
return WinJS.Promise.wrapError("No file selected");
}
}).then(function(stream) {
fileStream = stream;
var transform = new Windows.Graphics.Imaging.BitmapTransform();
return decoder.getPixelDataAsync(
decoder.bitmapPixelFormat,
decoder.bitmapAlphaMode,
transform,
Windows.Graphics.Imaging.ExifOrientationMode.respectExifOrientation,
Windows.Graphics.Imaging.ColorManagementMode.colorManageToSRgb
);
}).then(function (pixelProvider) {
pixels = pixelProvider.detachPixelData();
return Imaging.BitmapEncoder.createAsync(encoderId, fileStream);
}).then(function (encoder) {
encoding = decoder;
//Set the pixel data--assume "encoding" object has options from elsewhere
encoder.setPixelData(encoding.bitmapPixelFormat, encoding.bitmapAlphaMode,
encoding.pixelWidth, encoding.pixelHeight, encoding.dpiX, encoding.dpiY,
pixels);
//Go do the encoding
return encoder.flushAsync();
}).done(function () {
//Make sure to do this at the end
fileStream.close();
}, function () {
//Empty error handler (do nothing if the user canceled the picker
});
}
I've commented out the ability to save as JPG because that's a new problem, but this works for pngs
回答2:
Place your canvas within a Grid with background white and then render it using RenderTargetBitmap. It worked fine for me.
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync("Your Grid containing canvas goes here");
var pixelBuffer = await rtb.GetPixelsAsync();
var pixels = pixelBuffer.ToArray();
var displayInformation = DisplayInformation.GetForCurrentView();
FileSavePicker savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("png", new List<string>() { ".png" });
savePicker.SuggestedFileName = "PNG File";
StorageFile file = await savePicker.PickSaveFileAsync();
来源:https://stackoverflow.com/questions/53525526/saving-a-canvas-as-an-image-in-uwp