In my MVC project I generate an array of images and store the array as a session variable, I animate the images using slidebar and by detecting mouse movement while mouse button is down by calculating the distance between the first click and x position while the mouse is moving on a canvas.
In the controller I use:
public ActionResult Animate(int slice = 0, int udm = 0)
{
FileContentResult data;
Image objImage = null;
Bitmap im = null;
try
{
im = MySession.Current.imageArray[slice];
....
MySession.Current.image = im;
}
else
{
return RedirectToAction("Index",new {.... });
}
}
catch { }
return null;
}
and
public ActionResult ImageOut(int udm = 0)
{
FileContentResult data;
Image objImage = null;
Bitmap im = null;
im = MySession.Current.image;
...
objImage = im.Bitmap(outputSize, PixelFormat.Format24bppRgb, m);
MemoryStream ms1 = new MemoryStream();
using (var memStream = new MemoryStream())
{
objImage.Save(memStream, ImageFormat.Png);
data = this.File(memStream.GetBuffer(), "image/png");
}
objImage.Dispose();
return data;
}
From the view I use Ajax:
$.ajax({
url: '/Home/Animate',
type: 'POST',
async: false,
data: {
slice: ((lastX - firstX) + nSlice),
udm: ++udm
},
success: function(data) {
if (data.udm) {
nSlice = (data.slice);
image.src = '/Home/ImageOut?' + $.param({
udm: data.udm
});
}
},
error: function() {
}
});
I have two problems, first it takes time to update the view and skips a number of images, the second is it open many threads and if a number of users accessing the same page it slows down. I thought of using async but I am still using c# 4 and this may requires lots of changes to my code. I was reading about SignalR, my question is can this be done (providing I just update the user screen not all users) or is there a better solution.
The sequence of events I would like to achieve is:
Ajax send to the first action a request or generate the first image and wait
When the image is generated, Ajax receive success, then display the image on the screen using the second action
Then the first action generate the second image
The challenge I see is the first image keep generating the images without waiting, so my question is how I make the first action wait, and how to send to it a message to generate the following image.
I just installed VS2012 c#5, is there any example that can help me!! Would appreciate your suggestions, thanks in advance.
Using TPL, you could try this (taking your code above), the same can be applied for the animate method:
public ActionResult ImageOut(int udm = 0)
{
FileContentResult data = null;
Image objImage = null;
Task.Run(() =>
{
Bitmap im = MySession.Current.dicomImage;
objImage = im.Bitmap(outputSize, PixelFormat.Format24bppRgb, m);
using (var memStream = new MemoryStream())
{
objImage.Save(memStream, ImageFormat.Png);
data = this.File(memStream.GetBuffer(), "image/png");
}
});
objImage.Dispose();
return data;
}
Task.Run is just shorthand for Task.Factory.StartNew
Rather than changing my program to use TPL because of the learning curve; I just added async: false to my ajax; this helped to delay the refresh of the screen. Not the best approach but helped a bit.
Related
I have problems to drag an image from one iframe (1) out of a dynamic table to another iframe (2) within a droppable area. I think there is no permission issue, but a "type" issue. The drop area on iframe (2) is working with files from anywhere except form the iframe (1). The iframe (1) is hosted by localhost. The iframe (2) is hosted by a different domain.
Three different functions I found to convert data uri to file or blob were tested. The setData arguments also have been tested with all possibilities, no success by now.
Interestingly, having opened the site with the two iframes on Chrome and firefox, I am able to drag an drop from firefox to Chrome, but the image will be converted to bmp type and renamed! The other way around it is not working.
What are the right arguments for setData / get Data to drop an image
data uri on a drop area?
Do I have to convert data uri to a file
resp. blob object?
If so, again, what arguments will do the job?
Any help would be appreciated very much!
var dataUri;
var file;
function mouseDown(event){
toDataURL(event.target.src, function(dataUrl) {
console.log('RESULT:', dataUrl.replace('data:text/plain;base64,', ''));
dataUri = dataUrl.replace('data:text/plain;base64,', '');
file = urltoFile(dataUrl, 'hello.jpg','image/jpeg')
.then(function(file){ console.log(file);});
})
}
function drag(event) {
// event.stopPropagation();
console.log(file);
console.log(dataUri);
event.dataTransfer.setData("text/plain", file);
//event.dataTransfer.mozSetDataAt("application/x-moz-file", file, 0);
event.dataTransfer.effectAllowed = "move";
}
function drop(event) {
//event.preventDefault();
console.log(file);
console.log(dataUri);
var data = event.dataTransfer.getData("text/plain");
//var data = event.dataTransfer.mozGetDataAt("application/x-moz-file", 0);
event.target.appendChild(document.getElementById(data));
document.getElementsById(data);
console.log(data);
}
function allowDrop(event) {
event.preventDefault();
}
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
function urltoFile(url, filename, mimeType){
return (fetch(url)
.then(function(res){return res.arrayBuffer();})
.then(function(buf){return new File([buf], filename,{type:mimeType});})
);
}
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var dw = new DataView(ab);
for(var i = 0; i < byteString.length; i++) {
dw.setUint8(i, byteString.charCodeAt(i));
}
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], {type: mimeString});
}
I'm developing an app in angular dart and trying to animate a progress bar which shows progress of a file upload. I'm simply parsing the JSON from the file, and sending them off to a service with a _service.create(....) method.
I've put all of this code in an async method which is called when my submit button is clicked:
void uploadFile() async {
submitButton.attributes.addAll({ 'disabled': '' });
progress.value = 0;
FileList files = input.files;
if (files.isEmpty) {
_handleError("No file selected");
//handle error, probably a banner
return;
}
File file = files.item(0);
FileReader reader = new FileReader();
//reader.result
reader.onLoadEnd.listen((e) async {
Map map = json.decode(reader.result);
var combinations = map['combinations'];
progress.max = combinations.length;
int loopCount = 0;
combinations.forEach((e) async {
await _service.create(VJCombination.fromJSON(e)).then((_) {
combinationCount++;
progress.value++;
loopCount++;
if (loopCount == combinations.length) {
submitButton.attributes.remove('disabled');
}
});
});
isLoadSuccessful = true;
});
reader.onError.listen((evt) => print(evt));
reader.readAsText(file);
progress.value = 10;
}
I'm getting the progress and the submitButton elements with the #ViewChild annotations:
#ViewChild('progress')
ProgressElement progress;
#ViewChild('submit')
ButtonElement submitButton;
The code works. The progress bar starts off empty, and after the file is read and the service gets the data, the progress bar is full.
My issue is that the UI is only updated after all of the combinations have been sent to the _service. So it seemingly goes from empty to full in one frame.
This code
combinations.forEach((e) async {
does not make sense, because forEach does not care about the returned Future
Rather use
for(var e in combinations) {
Not sure if this fixes your problem, but such code definitely needs to be changed.
I'm trying to change the bitmap image in createjs and want to remove all children in a container when reset button is clicked. But removeAllChildren is not working in me.
function drawPhoneImage() {
stage = new createjs.Stage('canvas');
container = new createjs.Container();
phone = new createjs.Bitmap(phoneImg);
phone.x = 268;
phone.y = 64;
stage.addChild(container);
container.addChild(phone);
stage.update();
phone.addEventListener("click", function() {
console.log('phone clicked');
createjs.Ticker.addEventListener("tick", movePhoneImage);
});
}
function movePhoneImage(event) {
phone.x -=10;
if(phone.x < 156) {
phone.x =156;
showPhoneSnap();
}
stage.update(event);
}
Then after clicking the phone object, I'll need to replace it with another bitmap(which works):
function showPhoneSnap() {
snap = new createjs.Bitmap(snapImg);
snap.x = 156;
snap.y = 64;
container.removeAllChildren();
container.addChild(snap);
stage.update();
}
At first, removeAllChildren is working in the first child of the container, but when i tried resetting the stage after adding another bitmap in the container..removeAllChildren() is not working.
function resetStage() {
container.removeAllChildren();
stage.update();
}
I'm having a hard time solving this issue, thanks for anyone who can help.
Make sure that "snapImg" is an image that is loaded.
snap = new createjs.Bitmap(snapImg);
The issue is that you are not updating the stage when the image is loaded.
var image = new Image();
image.src = "path";
image.onload = showPhoneSnap;
function showPhoneSnap() {
//This will ensure that the image is ready.
var bmp = new createjs.Bitmap(this);
...
stage.update();
}
I am loading images for a game before the game begin. So the main function sends links of images to an image loading object. This is what happen in my image loading object when I do image.load(link) in my main :
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
trace("load");
urlRequest = new URLRequest(str);
loaderArray[cptDemande] = new Loader();
loaderArray[cptDemande].contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loaderArray[cptDemande].load(urlRequest);
posX[cptDemande] = img_x;
posY[cptDemande] = img_y;
layerArray[cptDemande] = layer;
cptDemande++;
}
The parameters img_x:int, img_y:int and layer:Sprite are related to displaying the images afterward. I am using arrays to be able to add the images to the stage when the loading is all done.
The event listener fire this function :
public function loading_done(evt:Event):void
{
cptLoaded++;
evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
what I want is to be able to target the good loader to remove the event listener. What I am currently using(evt.currentTarget) doesn't work and generate an error code :
1069 Property data not found on flash.display.LoaderInfo and there is no default value
Tracing evt.currentTarget shows that currentTarget is the LoaderInfo property. Try updating your code as follows:
public function loading_done(evt:Event):void
{
cptLoaded++;
// Current target IS the contentLoaderInfo
evt.currentTarget.removeEventListener(Event.COMPLETE, loading_done);
//evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
Just a wee tip for you while I'm at it, you could make life a lot easier for yourself by storing all the properties of your images on an Object and then pushing these onto a single Array, rather than managing a separate Array for each property.
Something like this:
private var loadedImages:Array = new Array();
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
var urlRequest:URLRequest = new URLRequest(str);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loader.load(urlRequest);
var imageData:Object = { };
imageData.loader = loader;
imageData.posX = img_x;
imageData.posY = img_y;
imageData.layer = layer;
// Now we have a single Array with a separate element for
// each image representing all its properties
loadedImages.push(imageData);
cptDemande++;
}
I'm using the iviewer plugin with a lightbox and I have issue to center my image everytime it load a new image.
I know that there is a pre-built method center() I just don't undertand how and where to call it.
You can find the function I'm using under. The function is called when I click on an element, it open a box div(#iviewer). In which I would like my image center. I also use a zoom pourcentage at the beginning so my image doesn't fit the box (var viewer).
function open(src, id) {
var firstZoom = true;
$("#iviewer").fadeIn().trigger('fadein');
var viewer = $("#iviewer .viewer").
width(920).
height(560).
iviewer({
src : src,
ui_disabled : true,
zoom : '50%',
initCallback : function() {
var self = this;
},
onZoom : function() {
if (!firstZoom) return;
$("#iviewer .loader").fadeOut();
$("#iviewer .viewer").fadeIn();
firstZoom = true;
}
}
);
//load new pic
viewer.iviewer('loadImage', src);
}
Thanks for the help.
The "onFinishLoad" callback hook in the initialization worked for me:
onFinishLoad: function(ev, src){ viewer.iviewer('center')}