在 UWP 中将 Canvas 保存为图像
Saving a Canvas as an image in UWP
我发现 this documentation 用于将 Canvas 导出并保存为 png。它给出了以下代码:
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
});
在 'encoder.setPixelData' 区域,他们使用一个名为 'encoding' 的对象来设置所有值,但没有解释在之前的任何步骤中如何创建该对象。
如何创建这个 'encoding' 对象来完成示例?
我找到了另一种方法来保存 canvas,仍然没有解决我最初的问题
我可以将 canvas 转换为 blob 流并将其保存到 png 文件
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
});
}
不幸的是,它以透明背景保存,但也许有办法让我的 canvas 具有白色背景。
[编辑] ----
所以我找到了一种更直接地回答我原来问题的方法:
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
});
}
我已经注释掉了另存为 JPG 的功能,因为这是一个新问题,但这适用于 png
将您的 canvas 放在背景为白色的网格中,然后使用 RenderTargetBitmap 对其进行渲染。它对我来说很好用。
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();
我发现 this documentation 用于将 Canvas 导出并保存为 png。它给出了以下代码:
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
});
在 'encoder.setPixelData' 区域,他们使用一个名为 'encoding' 的对象来设置所有值,但没有解释在之前的任何步骤中如何创建该对象。
如何创建这个 'encoding' 对象来完成示例?
我找到了另一种方法来保存 canvas,仍然没有解决我最初的问题
我可以将 canvas 转换为 blob 流并将其保存到 png 文件
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
});
}
不幸的是,它以透明背景保存,但也许有办法让我的 canvas 具有白色背景。
[编辑] ----
所以我找到了一种更直接地回答我原来问题的方法:
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
});
}
我已经注释掉了另存为 JPG 的功能,因为这是一个新问题,但这适用于 png
将您的 canvas 放在背景为白色的网格中,然后使用 RenderTargetBitmap 对其进行渲染。它对我来说很好用。
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();