StorageItemThumbnail to BitmapImage converter fails with MediaCapture mp4 - windows-runtime

I am using a ValueConverter to get the thumbnail for an m4 file that was recorded by directly with WinRT's MediaCapture. After much debugging and alternate approaches, I've settle on the converter code below. I am getting the following error The component cannot be found. (Exception from HRESULT: 0x88982F50) on the GetThumbnailAsync method.
I have confirmed that the thumbnail is being shown for the video in the Xbox Video app and the file explorer app when I use CopyTo(KnownFolders.VideosLibrary).
The converter seems to work fine when it's an external video file, but not with one of my app's mp4s. Is there something wrong with my converter or can you reproduce this?
SEE UPDATE 1 I try to get the thumbnail when the file is first created, same error occurs.
public class ThumbnailToBitmapImageConverter : IValueConverter
{
readonly StorageFolder localFolder = ApplicationData.Current.LocalFolder;
BitmapImage image;
public object Convert(object value, Type targetType, object parameter, string language)
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
return "images/ExamplePhoto2.jpg";
if (value == null)
return "";
var fileName = (string)value;
if (string.IsNullOrEmpty(fileName))
return "";
var bmi = new BitmapImage();
bmi.SetSource(Thumb(fileName).Result);
return bmi;
}
private async Task<StorageItemThumbnail> Thumb(string fileName)
{
try
{
var file = await localFolder.GetFileAsync(fileName)
.AsTask().ConfigureAwait(false);
var thumbnail = await file.GetScaledImageAsThumbnailAsync(ThumbnailMode.ListView, 90, ThumbnailOptions.UseCurrentScale)
.AsTask().ConfigureAwait(false);
return thumbnail;
}
catch (Exception ex)
{
new MessageDialog(ex.Message).ShowAsync();
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
UPDATE 1
I decided to go back to where I save the video to a file and grab the thumbnail there, then save it to an image for use later. I get the same error, here is the code for grabbing and saving the thumbnail after the video is saved:
var thumb = await videoStorageFile.GetThumbnailAsync(ThumbnailMode.ListView);
var buffer = new Windows.Storage.Streams.Buffer(Convert.ToUInt32(thumb.Size));
var thumbBuffer = await thumb.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None);
using (var str = await thumbImageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await str.WriteAsync(thumbBuffer);
}

I have not tested this out, but It should work. In your model that you are binding to, replace the property for your thumbnail with a new class named Thumbnail. Bind to that property rather than your video location. When the video location changes, create a new thumbnail.
public class VideoViewModel : INotifyPropertyChanged
{
public string VideoLocation
{
get { return _location; }
set
{
_location = value;
Thumbnail = new Thumbnail(value);
OnPropertyChanged();
}
}
public Thumbnail Thumbnail
{
get { return _thumbnail; }
set
{
_thumbnail = value;
OnPropertyChanged();
}
}
}
The Thumbnail class. This is just a shell, ready for you to fill out the rest
public class Thumbnail : INotifyPropertyChanged
{
public Thumbnail(string location)
{
Image = GetThumbFromVideoAsync(location);
}
private Task<BitMapSource> GetThumbFromVideoAsync(string location)
{
BitMapSource result;
// decode
// set it again to force
Image = Task.FromResult(result);
}
public Task<BitMapSource> Image
{
get { return _image; }
private set
{
_image = value;
OnPropertyChanged();
}
}
}
You can still have a value converter in place. It would check if the task has completed, if it has not, then show some default image. If the task has faulted, it can show some error image:
public class ThumbnailToBitmapImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var thumbnail = value as Thumbnail;
if (thumbnail == null) return GetDefaultBitmap();
if (thumbnail.Image.IsCompleted == false) return GetDefaultBitmap();
if (thumbnail.Image.IsFaulted) return GetBadImage();
return thumbnail.Image.Result;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
private BitMapSource GetDefaultBitmap()
{
// load a default image
}
private BitMapSource GetBadImage()
{
// load a ! image
}
}

Related

Fresco using DataSubscriber to load gif

I wanna get the gif through DataSubscriber by Fresco.But when i get the CloseableAnimatedImage, I don't know how to get the bitmap of it.
public void getBitmap(String url, final OnBitmapFetchedListener listener) {
ImageRequest request = ImageRequest.fromUri(Uri.parse(url));
final ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>>
dataSource = imagePipeline.fetchDecodedImage(request, null);
DataSubscriber dataSubscriber = new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
#Override
protected void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> closeableReferenceDataSource) {
CloseableReference<CloseableImage> imageReference = closeableReferenceDataSource.getResult();
if (imageReference != null) {
try {
CloseableImage image = imageReference.clone().get();
if (image instanceof CloseableAnimatedImage) {
//here i get the gif but i don't know how to get the bitmap
}
}
}
}
and i tried another way to get the bitmap of a pic:
fun getBitmap(uri: Uri, listener: OnBitmapFetchedListener) {
val request = ImageRequest.fromUri(uri)
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.fetchEncodedImage(request, null)
val dataSubscriber = object : BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
override fun onNewResultImpl(closeableReferenceDataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
val imageReference = closeableReferenceDataSource.result
if (imageReference != null) {
try {
val image = imageReference.clone().get()
val inputStream = PooledByteBufferInputStream(image)
val imageFormat = ImageFormatChecker.getImageFormat(inputStream)
Log.e("ImageUtil", "imageFormat = ${ImageFormat.getFileExtension(imageFormat)}")
val bitmap = BitmapFactory.decodeStream(inputStream)
listener.onSuccess(bitmap)
} catch (e: IOException) {
Log.e("ImageUtil", "error:$e")
} finally {
imageReference.close()
}
}
}
override fun onFailureImpl(closeableReferenceDataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
Log.e("ImageUtil", "fail")
listener.onFail()
}
}
It's kotlin code, what i do is using fetchEncodedImage and get the inputStream of a pic.
But it always go onFailImpl(), I don't know why.
It seems that the real question is how to statically display only the first frame of an animated image. This is not supported at the moment, but it would be very easy to implement.
Fresco already has ImageDecodeOptions object. You would just need to add another field there: public final boolean decodeAsStaticImage. Then in ImageDecoder.decodeGif you just need to change:
if (GifFormatChecker.isAnimated(is)) {
return mAnimatedImageFactory.decodeGif(...);
}
return decodeStaticImage(encodedImage);
to:
if (!options.decodeAsStaticImage && GifFormatChecker.isAnimated(is)) {
return mAnimatedImageFactory.decodeGif(...);
}
return decodeStaticImage(encodedImage);
Please feel free to implement this and make a pull request to our GitHub Fresco repository.
And then in the client code, you just need to set your decode options to the image request with ImageRequestBuilder.setImageDecodeOptions.

I want to create highchart widget by Eclipse RAP and i follow "RAP/Custom Widgets FAQ",but there is error?

i want to create some highchart widget by Eclipse RAP ,and i follow the official guide like this
handlejs:
var CKEDITOR_BASEPATH = "rwt-resources/";
(function(){
'use strict';
rap.registerTypeHandler( "rap.sunline.HighCharts", {
factory : function( properties ) {
var parent = rap.getObject( properties.parent );
// var element = document.createElement( "div" );
// parent.append( element );
// $(element).html("askldfjaskljdk");
return {};
}
});
}());
widget.java:
public class HightChartComposite extends Composite {
private static final String RESOURCES_PATH = "resources/";
private static final String REGISTER_PATH = "hightcharts/";
private static final String[] RESOURCE_FILES = { "jquery-2.1.0.min.js", "highcharts.js","ChartPaintListener.js" };
private static final String REMOTE_TYPE = "rap.sunline.HightCharts";
private final RemoteObject remoteObject;
private final OperationHandler operationHandler = new AbstractOperationHandler() {
#Override
public void handleSet(JsonObject properties) {
// JsonValue textValue = properties.get("text");
// if (textValue != null) {
// text = textValue.asString();
// }
}
};
public HightChartComposite(Composite parent, int style) {
super(parent, style);
registerResources();
loadJavaScript();
Connection connection = RWT.getUISession().getConnection();
remoteObject = connection.createRemoteObject(REMOTE_TYPE);
remoteObject.setHandler(operationHandler);
remoteObject.set("parent", WidgetUtil.getId(this));
}
private void registerResources() {
ResourceManager resourceManager = RWT.getResourceManager();
boolean isRegistered = resourceManager.isRegistered(REGISTER_PATH + RESOURCE_FILES[0]);
if (!isRegistered) {
try {
for (String fileName : RESOURCE_FILES) {
register(resourceManager, fileName);
}
} catch (IOException ioe) {
throw new IllegalArgumentException("Failed to load resources", ioe);
}
}
}
private void loadJavaScript() {
JavaScriptLoader jsLoader = RWT.getClient().getService(JavaScriptLoader.class);
ResourceManager resourceManager = RWT.getResourceManager();
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "jquery-2.1.0.min.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "highcharts.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "ChartPaintListener.js"));
}
private void register(ResourceManager resourceManager, String fileName) throws IOException {
ClassLoader classLoader = HightChartComposite.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(RESOURCES_PATH + fileName);
try {
resourceManager.register(REGISTER_PATH + fileName, inputStream);
} finally {
inputStream.close();
}
}
// //////////////////
// overwrite methods
#Override
public void setLayout(Layout layout) {
throw new UnsupportedOperationException("Cannot change internal layout of CkEditor");
}
}
the error is occur:
Uncaught Error: Operation "create" on target "r6" of type "null" failed:
No Handler for type rap.sunline.HightCharts
Properties:
parent = w5
and i have a question about this , what differents from extends Canvas and Composite;
You forget to implement setters in your javascript code.
The created object is stored by the framework under its object id. This object has to implement setter methods that match the properties defined in the handler, which will then be called when the server sends a set operation for a given property.

Webapi custom JsonMediaTypeFormatter

I am trying to create a custom JSONMediaTypeFormatter in which posts some json parameters to a webapi call. I need to encrypt the returned data from the webapi, hence writing a custom mediatypeformatter.
In my webapiconfig I clear all formatters and only add the custom formatter.
config.Formatters.Clear();
config.Formatters.Add(new CipherMediaFormatter());
In my custom media type formatter I add in the relevant headers and types but i still cant call my web api. It gives me an error
No MediaTypeFormatter is available to read an object of type 'Param' from content with media type 'application/json
The code for the mediatypeformatter
public class CipherMediaFormatter : JsonMediaTypeFormatter
{
private static Type _supportedType = typeof(object);
public CipherMediaFormatter()
{
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.ContentType = new MediaTypeHeaderValue("application/json");
}
public override bool CanReadType(Type type)
{
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var taskSource = new TaskCompletionSource<object>();
try
{
var ms = new MemoryStream();
readStream.CopyTo(ms);
taskSource.SetResult(ms.ToArray());
}
catch (Exception e)
{
taskSource.SetException(e);
}
return taskSource.Task;
}
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
var taskSource = new TaskCompletionSource<object>();
try
{
if (value != null)
{
var jsonData = JsonConvert.SerializeObject(value);
ICryptographicService cgService = new CryptographicService();
string apiKey = string.Empty;
string pattern = #"api\/(.*)?\/(\d+)?";
var match = Regex.Match(HttpContext.Current.Request.RawUrl, pattern);
....
}
}
catch (Exception e)
{
taskSource.SetException(e);
}
return taskSource.Task;
}
}
The problem was ReadFromStreamAsync causing the mediatypeformatter to error.

Windows Phone 8 ImageSource cannot be serialized Error while sharing image

i am trying to share an image. I got a picture object and am getting the path from it. When I'm calling the ShareMediaTask it throw following error:
System.Windows.Media.ImageSource cannot be serialized.
I am still able to share the image, but the app crashes when returning from sharing.
Here is my code:
PictureModel picture = Singleton.Instance.BearPicture.Model.Images.Where(PictureModel => PictureModel.Bmp.UriSource == (Image_View.Source as BitmapImage).UriSource).FirstOrDefault();
var task = new ShareMediaTask();
task.FilePath = picture.Picture.GetPath();
task.Show();
My PictureModel looks like this:
public class PictureModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _uri;
public string Uri
{
get { return _uri; }
set
{
if (value != _uri)
{
_uri = value;
NotifyPropertyChanged("Uri");
}
}
}
private string _relativePath;
public string RelativePath
{
get { return _relativePath; }
set
{
if (_relativePath != value)
{
_relativePath = value;
NotifyPropertyChanged("RelativePath");
}
}
}
private BitmapImage _bmp;
public BitmapImage Bmp
{
get { return _bmp; }
set
{
if (value != _bmp)
{
_bmp = value;
NotifyPropertyChanged("Bmp");
}
}
}
private Picture _picture;
public Picture Picture
{
get { return _picture; }
set
{
if (value != _picture)
{
_picture = value;
NotifyPropertyChanged("Picture");
}
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Where does this error come from? I am only getting the Source of my image object but i am not doing anything else with it. My picture is also saved in the media library like this:
myFileStream = myStore.OpenFile(fileName, FileMode.Open, FileAccess.Read);
MediaLibrary library = new MediaLibrary();
Picture pic = library.SavePicture(fileName, myFileStream);
On Appstart im searching through my savedpicture folder, to get the picture object, which is then saved in my PictureModel.
Any help is appreciated.
Thanks in advance.
robidd
This may help: Crashes Back (WriteableBitmap cannot be serialized) windows phone 8. See the comment from KooKiz.
"Same symptoms, same cause. You've stored at some point an ImageSource in the phone state (probably PhoneApplicationService.Current.State or IsolatedStorageSettings.ApplicationSettings). You have to find where!"
Apparently we can cause this error indirectly. I'm having a similar problem and I found that answer and also your own question.
Hope it helps.
Cheers.

Enable WCF Data Service to accept/return JSON by default

I have a WCF Data Service that I'd like to return JSON by default for all operations. Is there a place I can set that in configuration/via service attributes?
In order to enable json via the $format tag like this:
host:8038/YourService.svc/?$format=json
Add this attribute to your service declaration:
[JSONPSupportBehavior]
public class Service : DataService<YourEntities>
Add this as a class to your service:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Xml;
namespace YourNamespaceHere.Service
{
public class JSONPSupportInspector : IDispatchMessageInspector
{
// Assume utf-8, note that Data Services supports
// charset negotation, so this needs to be more
// sophisticated (and per-request) if clients will
// use multiple charsets
private static Encoding encoding = Encoding.UTF8;
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (request.Properties.ContainsKey("UriTemplateMatchResults"))
{
HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
UriTemplateMatch match = (UriTemplateMatch)request.Properties["UriTemplateMatchResults"];
string format = match.QueryParameters["$format"];
if ("json".Equals(format, StringComparison.InvariantCultureIgnoreCase))
{
// strip out $format from the query options to avoid an error
// due to use of a reserved option (starts with "$")
match.QueryParameters.Remove("$format");
// replace the Accept header so that the Data Services runtime
// assumes the client asked for a JSON representation
httpmsg.Headers["Accept"] = "application/json";
string callback = match.QueryParameters["$callback"];
if (!string.IsNullOrEmpty(callback))
{
match.QueryParameters.Remove("$callback");
return callback;
}
}
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
if (correlationState != null && correlationState is string)
{
// if we have a JSONP callback then buffer the response, wrap it with the
// callback call and then re-create the response message
string callback = (string)correlationState;
XmlDictionaryReader reader = reply.GetReaderAtBodyContents();
reader.ReadStartElement();
string content = JSONPSupportInspector.encoding.GetString(reader.ReadContentAsBase64());
content = callback + "(" + content + ")";
Message newreply = Message.CreateMessage(MessageVersion.None, "", new Writer(content));
newreply.Properties.CopyProperties(reply.Properties);
reply = newreply;
}
}
#endregion
class Writer : BodyWriter
{
private string content;
public Writer(string content)
: base(false)
{
this.content = content;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Binary");
byte[] buffer = JSONPSupportInspector.encoding.GetBytes(this.content);
writer.WriteBase64(buffer, 0, buffer.Length);
writer.WriteEndElement();
}
}
}
// Simply apply this attribute to a DataService-derived class to get
// JSONP support in that service
[AttributeUsage(AttributeTargets.Class)]
public class JSONPSupportBehaviorAttribute : Attribute, IServiceBehavior
{
#region IServiceBehavior Members
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.MessageInspectors.Add(new JSONPSupportInspector());
}
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
#endregion
}
}
You could add an extension as per this download.
http://archive.msdn.microsoft.com/DataServicesJSONP
You would still need to customise it as the code is checking to see if you are asking for JSON formatting via the URL.e.g $format=json.