Getting image from webapi causes memory leak - javascript

I have a aurelia client that gets a image from my asp.net server via my API. The image is served from the server that holds a Emgu CV UMat var. With the following method in my controller i get the image and it is displayed correctly.
This method results in memory leakage and i can't seem to get to the orgin (not calling the method, means no leak):
Update, i tried Mawg's suggestion but when i close the stream it will not show the image. The leak is gone then but there is no image.
[System.Web.Http.HttpGet]
[System.Web.Http.Route("dummymethod3")]
public HttpResponseMessage Get2()
{
HttpResponseMessage response = new HttpResponseMessage();
try
{
Console.WriteLine("Get image 3");
ddEngine.sem.WaitOne();
var memoryStream = new MemoryStream();
ResultImage.Bitmap.Save(memoryStream, ImageFormat.Png);
memoryStream.Position = 0;
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(memoryStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
memoryStream.Close();
memoryStream.Dispose();
ddEngine.sem.Release();
return result;
}
catch
{
Console.WriteLine("Ex");
}
return response;
}
I have tried to call the collector at several places in the code like:
GC.Collect();
GC.WaitForPendingFinalizers();
When doing this it releases resources but the memory usege is slowly increasing. When not calling the get method there is no increase!
My client code looks like this:
updateImageSrc() {
let dt = new Date();
let baseUrl = "http://localhost:8080/api/status/dummymethod3";
this.imagePath = baseUrl + "?t=" + dt.getTime();
}
And the html
<img id="img" src.bind="imagePath"/>
Any suggestions are welcome!

Related

Creating a new Image object from a memory stream is not working in production, but works locally

The Goal: I am currently taking a file from javascript, converting it into a base64 encoded string of a byte array and passing it to my .net controller.
I am then processing that by converting that back into a byte array, creating a new memory stream of it, creating an Image object from the memory stream, changing what I need to change about it, and then bringing it back into a memory stream to then upload to my server.
The problem:
I currently am able to take an image in from JavaScript encoded like I had mentioned earlier, and upload it to the server no problem, however the issue comes in when I am trying to convert my memory stream to an Image (so that I can resize it). I am not sure why, but on my local machine it has no problems and doesn't throw any errors and uploads perfectly fine, resized and everything. However on my linux server, it gets to the log line right before it try's to create the image from the memory stream, it doesn't actually throw an exception, but just stops working and returns to my controller.
I am not really sure what is going on but hopefully some of you fine people can help :).
The code:
public async Task<DataOpResult<string>> UploadFile(StorageUploadFile file, string FileGuid)
{
Console.WriteLine("Start Upload");
DataOpResult<string> uploadFile = new DataOpResult<string>();
uploadFile.Status = DataOpResultStatus.Success;
try
{
//create storage client
StorageClient storage = await StorageClient.CreateAsync(credential);
Console.WriteLine("Created storage");
//convert file data and create Image Object
byte[] dataArray = Convert.FromBase64String(file.FileData);
Console.WriteLine("Got byte array");
Image imageVar = CreateImage(dataArray);
Console.WriteLine("Converted image");
//convert with aspect ratio
var aspectRatio = (decimal)(imageVar.Width) / (decimal)(imageVar.Height);
var newHeight = 150;
int newWidth = (int)(newHeight * aspectRatio);
//Resize Image
Console.WriteLine("Resize image");
Image resizedImage = ResizeImage(imageVar, newWidth, newHeight);
MemoryStream resizedStream = new MemoryStream();
resizedImage.Save(resizedStream, imageVar.RawFormat);
Console.WriteLine("got new memory stream");
// IUploadProgress defined in Google.Apis.Upload namespace
var progress = new Progress<IUploadProgress>(
p => Console.WriteLine($"bytes: {p.BytesSent}, status: {p.Status}")
);
// var acl = PredefinedAcl.PublicRead // public
var acl = PredefinedObjectAcl.AuthenticatedRead; // private
var options = new UploadObjectOptions { PredefinedAcl = acl };
Console.WriteLine("Upload Images");
var result = await storage.UploadObjectAsync("echochat-292801.appspot.com", $"{FileGuid}/{file.FileName}", file.FileType, resizedStream, options, progress: progress);
Console.WriteLine(result.ToString());
uploadFile.DataItem = result.MediaLink;
} catch (Exception ex)
{
uploadFile.Status = DataOpResultStatus.Error;
uploadFile.ThrownException = ex;
}
return uploadFile;
}
public static Image CreateImage(byte[] imageData)
{
Image image;
using (MemoryStream inStream = new MemoryStream())
{
inStream.Write(imageData, 0, imageData.Length);
image = Image.FromStream(inStream);
}
return image;
}
Running sudo apt-get install libgdiplus
on the my server ended up working!

Calling javascript string function on browser from Unity returns null

I have a WebGL unity project which attempts to execute javascript code on the browser and return a value.
I have the following .jslib file in my Assets/Plugins/WebGL folder:
var BrowserPlugin = {
GetEndpointURL: function()
{
var endpoint = window.itd.getEndpointUrl();
console.log("endpoint: " + endpoint);
return endpoint;
}
};
mergeInto(LibraryManager.library, BrowserPlugin);
In my c# code in unity, I import the dll and call my javascript method like so:
[DllImport("__Internal")]
private static extern string GetEndpointURL();
string endpointURL = GetEndpointURL();
The problem is, in my c# code the endpointUrl variable is always null. However, in my browser console, I can clearly see the correct value is logged in the browser javascript before I return it. What is causing this value to come back to unity as null?
This is your code:
GetEndpointURL: function()
{
var endpoint = window.itd.getEndpointUrl();
console.log("endpoint: " + endpoint);
return endpoint;
}
You cannot return string (endpoint) directly. You have to create a buffer to hold that string and this process includes allocating memory with _malloc and copying old string to that new memory location with writeStringToMemory.
GetEndpointURL: function()
{
var endpoint = window.itd.getEndpointUrl();
console.log("endpoint: " + endpoint);
var buffer = _malloc(lengthBytesUTF8(endpoint) + 1);
writeStringToMemory(endpoint, buffer);
return buffer;
}

Download selected files in knockout js

I need to download the selected files in a grid on download button click. I am using knokout.js and web api
Using the below given response I was able to download a single file
self.DownloadDoc = function () {
window.location.assign("http://localhost:8092/api/Document/GetResponse?id=" + self.selectedDocuments()[0]);
self.selectedDocuments.removeAll();
self.bindDocuments();
};
I tried looping this window.location.assign() code using for loop,but as it is synchronous call,its downloading only one file.
Html part
<span>Download</span><small></small>
Web Api code
[HttpGet]
public HttpResponseMessage GetResponse(string id)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
List<DocumentsModel> documents = _service.GetDocumentContent(Convert.ToInt32(id));
byte[] fileBytes = documents.FirstOrDefault().FileContent;
System.Net.Http.Headers.MediaTypeHeaderValue mediaType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
if (fileBytes != null)
response.Content = new ByteArrayContent(fileBytes);
response.Content.Headers.ContentType = mediaType;
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = documents.FirstOrDefault().FileLeafRef;
return response;
}
this part self.selectedDocuments()[0], looks like it will force download always only of first document.
Not sure what is your structure and output of selectedDocuments(),
for example, if it outputs array, with fileID nodes, maybe you should try with this:
<div data-bind="foreach: self.selectedDocuments()">
<span>Download</span><small></small>
</div>
then, you will have to pass param in function:
self.DownloadDoc = function (fileID) {
window.location.assign("http://localhost:8092/api/Document/GetResponse?id=" + fileID);
self.selectedDocuments.removeAll();
self.bindDocuments();
};

Capture audio with naudio and play with javascript

I have a client with written c# and a server with written java. I capture audio and send with socket to the server and server send with web socket to the browser and want to play with browser. But when i try browser says Uncaught (in promise) DOMException: Failed to load because no supported source was found.
Could you help me?
private static void Recordwav()
{
waveInEvent = new WaveInEvent();
int devicenum = 0;
for (int i = 0; i < WaveIn.DeviceCount; i++)
{
if (WaveIn.GetCapabilities(i).ProductName.Contains("icrophone"))
devicenum = i;
}
waveInEvent.DeviceNumber = devicenum;
waveInEvent.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(devicenum).Channels);
waveInEvent.DataAvailable += new EventHandler<WaveInEventArgs>(VoiceDataAvailable);
waveInEvent.StartRecording();
}
private static void VoiceDataAvailable(object sender, WaveInEventArgs e)
{
JObject jObject = new JObject();
jObject["voice"] = Convert.ToBase64String(e.Buffer);
byte[] messageByte = Encoding.ASCII.GetBytes(jObject.ToString().Replace("\r\n", "") + "\n");
socket.Send(messageByte);
}
$scope.socket.onmessage = function (response)
{
var data = JSON.parse(response.data);
if(data.id == $scope.id) {
if(data.voice) {
var voice = data.voice;
var sound = new Audio("data:audio/wav;base64," + voice);
sound.play();
}
}
};
you're just sending raw samples, not a properly formatted WAV file. You'd need to use WaveFileWriter to write to a MemoryStream (wrapped in an IgnoreDisposeStream) dispose the WaveFileWriter and then access the MemoryStream underlying byte array. Also you're not taking into account BytesRecorded.
Even if you get this working, I suspect you'll get very choppy audio, as each WAV file will be a few hundred ms, and they won't necessarily play perfectly one after the other.

Add javascript to pdf file using iTextSharp

I want to embed a javascript snippet inside of a pdf file so that it will immediately print when it's opened from a browser window. To try and achieve this I'm following this example here.
I have created a helper class that has a static method to handle this task. I already have the pdf file path string ready to pass into the method. What I don't understand is how the output stream portion of this works. I would like the updated pdf to be saved to my servers hard drive. I do not want to stream it back to my browser. Any guidance would be greatly appreciated.
public class PdfHelper
{
public static void AddPrintFunction(string pdfPath, Stream outputStream)
{
PdfReader reader = new PdfReader(pdfPath);
int pageCount = reader.NumberOfPages;
Rectangle pageSize = reader.GetPageSize(1);
// Set up Writer
PdfDocument document = new PdfDocument();
PdfWriter writer = PdfWriter.GetInstance(document, outputStream);
document.Open();
//Copy each page
PdfContentByte content = writer.DirectContent;
for (int i = 0; i < pageCount; i++)
{
document.NewPage();
// page numbers are one based
PdfImportedPage page = writer.GetImportedPage(reader, i + 1);
// x and y correspond to position on the page
content.AddTemplate(page, 0, 0);
}
// Inert Javascript to print the document after a fraction of a second to allow time to become visible.
string jsText = "var res = app.setTimeOut(‘var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);’, 200);";
//string jsTextNoWait = “var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);”;
PdfAction js = PdfAction.JavaScript(jsText, writer);
writer.AddJavaScript(js);
document.Close();
}
}
For how to accomplish this task, please take a look at this and this SO posts.
Basically you should have something like this:
var pdfLocalFilePath = Server.MapPath("~/sourceFile.pdf");
var outputLocalFilePath = Server.MapPath("~/outputFile.pdf");
using (var outputStream = new FileStream(outputLocalFilePath, FileMode.CreateNew))
{
AddPrintFunction(pdfLocalFilePath, outputStream);
outputStream.Flush();
}

Categories