Copying three JS rendered canvas to another canvas fails on desktop Safari - safari

I need to copy a canvas rendered with three.js to another canvas by using the drawImage method of the canvas context.
ctx.drawImage(renderer.domElement, 0, 0);
It works like expected on Chrome and Firefox but doesn't work at all on my desktop Safari. I tried to specify the texture format but it didn't make any difference. Anyone knows the trick?
Here's a codepen with the three.js script.
http://codepen.io/anon/pen/BNvzMJ

This code works on safari but it flips the image upside down and the framerate goes down by 50% so it's definitely not ideal.
http://codepen.io/anon/pen/VLqmRO
var gl = renderer.getContext();
var width = renderer.domElement.width;
var height = renderer.domElement.height;
var size = width * height * 4;
var pixels = new Uint8Array(size);
var image = ctx.createImageData(width, height);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
for (var i = 0; i < size; i++) {
image.data[i] = pixels[i];
}
ctx.putImageData(image, 0, 0);

Why not use canvas.getImageData?
var width = renderer.domElement.width;
var height = renderer.domElement.height;
var imgData = gl.getImageData(0, 0, width , height);
ctx.drawImage(imgData, 10, 70);

Related

Camera position cause objects to disappear

I'm developing an app with blazor client-side and I need to render a 3D scene.
I have an issue and I guess it is material-related.
I have a composition of parallelepipeds where one of them is fully opaque and the others are transparent.
Depending on the camera angle, the transparent ones completely disappear:
Example where everything is visible:
Example with 2 missing:
Example with all missing:
Code for transparent parallelepipeds
var geometry = new THREE.CubeGeometry(item.xDimension * _scene.normalizer, item.yDimension * _scene.normalizer, item.zDimension * _scene.normalizer);
var material = new THREE.MeshBasicMaterial();
var box = new THREE.Mesh(geometry, material);
box.material.color = new THREE.Color("gray");
box.material.opacity = 0.8;
box.material.transparent = true;
Code for the camera:
var camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 100);
camera.position.set(1.3, 1.3, 1.3);
camera.lookAt(0, 0, 0);
I'm using OrbitControls and every object size is between 0 an 1 (_scene.normalizer is for that purpose)
Do you know why this is happening?
Edit:
I found it being a material depth function issue. Do you know which should I use?
Thanks,
Transparency is tricky with WebGL because a transparent object writes to the depthmap, and then the renderer assumes that subsequent objects behind it are occluded so it skips drawing them. You could avoid this by playing with the material's .depthTest and .depthWrite attributes (see the docs):
box.material.color = new THREE.Color("gray");
box.material.opacity = 0.8;
box.material.transparent = true;
box.material.depthWrite = false;

Resizing transparent jpeg generates image with black background

I am resizing images using Image Resizer. Everything's working as expected except one of our clients posted transparent jpeg, and resizing that image to 64*64 dimensions generates an image with black background. However, it works fine if the dimensions are larger like 1024.
var instructions = new Instructions
{
Height = 64,
Mode = FitMode.Max,
OutputFormat = "jpeg",
Width = 64
};
var job = new ImageJob(inputStream, outputStream, instructions);
job.DisposeSourceObject = false;
job.InstructionsAsString += "&fastscale=true";
job.Build();
"fastscale=true" was creating a problem in my case. So for all heights and widths that are greater than 75, it works as expected.
So I added following check to not include it for small dimensions
if (height >= 75 && width>= 75)
{
job.InstructionsAsString += "&fastscale=true";
}

Image Alignment when using resizeMode = contain

I'm using React Native's Image tag to display an image with a variable width and height. I have set the Image to 100x50 and set the resizeMode = contain which works almost perfectly, however if the image is resized, it's coming out completely centered vertically and horizontally. Can this behavior be altered? Mockup screenshot :
The red box indicates the Image element set at 100x50. The laptop pic represents the variable width/height picture. You'll notice that the behavior is pushing everything centered either vertically or horizontally.
In the second example, I would like the picture that takes up 100% of the height and roughly half the width to be pushed to be left aligned. Is this possible?
Thanks!
All - to possibly save some time in the future, this is a quick and dirty method I came up with to resolve this :
logoSize(width, height) {
var maxWidth = 110;
var maxHeight = 30;
if (width >= height) {
var ratio = maxWidth / width;
var h = Math.ceil(ratio * height);
if (h > maxHeight) {
// Too tall, resize
var ratio = maxHeight / height;
var w = Math.ceil(ratio * width);
var ret = {
'width': w,
'height': maxHeight
};
} else {
var ret = {
'width': maxWidth,
'height': h
};
}
} else {
var ratio = maxHeight / height;
var w = Math.ceil(ratio * width);
if (w > maxWidth) {
var ratio = maxWidth / width;
var h = Math.ceil(ratio * height);
var ret = {
'width': maxWidth,
'height': h
};
} else {
var ret = {
'width': w,
'height': maxHeight
};
}
}
return ret;
}
This will take a width and height of an image, run through some ratio calculations, and spit out a set of dimensions based on maxWidth and maxHeight vars at the top. You can then take the dimensions the method above gives you and apply it to an Image element e.g. :
var dims = logoSize(244,127);
<Image style={[styles.logo, {width:dims.width, height:dims.height}]} source={{uri:'/path/to/image.png}} />
Since the calculations rounds, you may need to apply the resizeMode:'contain' to the styles.logo in your Stylesheet.
Hope this saves someone some time.
I've solved a similar task the following way. First you need to set the initial Image styles:
initialImageStyle : { flex:1, resizeMode:'cover' }
This will render the Image in it's original size that we want to capture in a specific onLayout callback. So the trick is to implement that callback in a following manner:
onLayout (e) {
if (this.state.imageSize) { return }
const { x, y,
height,
width } = e.nativeEvent.layout,
sizeX = width - x,
sizeY = height - y,
imageWidth = (sizeX / sizeY) * IMAGE_HEIGHT
this.setState ({ imageSize: { height: IMAGE_HEIGHT, width: imageWidth, resizeMode: 'contain', }})
}
where IMAGE_HEIGHT is a constant height of your image container. Now all you have to do is just substitute the initial image styles using the state:
<Image
style={ this.state.imageSize || styles.initialImageStyle }
source={ /* your image */ }
onLayout={ this.onLayout.bind (this) }
/>
That's it. In your case you may also need to wrap an image in an additional View. Hope this will help.
Good luck!
It is quite possible but don't expect react-native to take care of everything. You may want to write a small algorithm to make this happen. What resizeMode="contain" does is that it checks whether the size of the image is greater/less than the container. If it is greater than the container, it will be resized to fit the container. If it is smaller than the container, it will be rendered as it is.
Regarding the alignment of the image, react-native doesn't really care. Images are placed at the middle of the container. If you want to place the image left-aligned, you'll have to write a small algorithm which compares the actual dimensions of the image and dimensions of the container.
For eg. If the height of the image is greater than the container, set the height of the image equal to the height of the container and calculate the width of the container using "aspect ratio". Read this to get a clear idea of what you'll have to do.
Also, play with position: 'absolute' to better suit your needs. Good luck!
Edit: Sorry for not deriving a ready-made solution for you. You might find the desired algorithm on google though. I just shoved you in the right direction.

Adding Image to Xaml not rendering with given margin

for (int i = 0; i < length; i++)
{
Image img1 ;
img1 = null;
img1= new Image();
img1.Height = snhei;
img1.Width = snwid;
BitmapImage BitImg = new BitmapImage(new Uri("/Assets/midtail.png", UriKind.Relative));`
img1.VerticalAlignment = VerticalAlignment.Top;
img1.HorizontalAlignment = HorizontalAlignment.Left;
img1.Source = BitImg;
img1.Stretch = Stretch.Fill;
img1.Name = "mid" + i.ToString() ;
img1.Margin = new Thickness(image_width*i, 0, 0, 0);
stackp.Children.Add(img1);
}
after running i get first image at 0,0
then it is render the one image_width below
The problem is your container. The StackPanel will, as it name indicates, try to stack the images. Then you apply the margin, moving the picture farther away.
You have two solutions, depending on what you want:
If you just want the images to be displayed side by side, set the Orientation property of your StackPanel to Horizontal. Then, remove your line of code that sets the margin, since the positioning is automatically handled by the StackPanel
If you still want to position the pictures manually, then you have to use another type of container. Replace your StackPanel by a Canvas or a Grid.

AndEngine visible rectangle

I'm trying to create an additional visibility rectangle on a main Scene.
So I'v a main Camera 480x800 that is showing me a scene as it is and i'd like to attach an aditional entity or a scene that will have a rectangle of visibility.
So if I'll drag items inside it they will not dissapier in a single moment they will dissapier gradually.
As described in my previous comment you could stamp out a square alpha hole in your background Sprite. You could do this simply with an image editor, adding alpha pixels or you could do it dynamically as follows,
//set the background to white - so we can see our square alpha
//cut out later
mScene.setBackground(new ColorBackground(1.0f, 1.0f, 1.0f));
//Create and load bitmap texture atlas
BitmapTextureAtlas mBitmapBGTextureAtlas = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
mActivity.getEngine().getTextureManager().loadTextures(mBitmapBGTextureAtlas);
//Get image in assets and decode into bitmap
InputStream ims;
try {
ims = mActivity.getAssets().open("gfx/my_backgound.jpg");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
Bitmap Bitmap_bg = BitmapFactory.decodeStream(ims);
//In my case the image is different than the height and width of the camera
//so store the ratio of size and height that the image will be resized to
float XScale = Bitmap_bg.getWidth()/mCamera.getWidth();
float YScale = Bitmap_bg.getHeight()/mCamera.getHeight();
//Cut out the alpha square, if our camera is 480x800, the square will appear
//at (40,200) and will be size 400x400
Bitmap_bg = cutSquareOutOfBitmap(Bitmap_bg, 40 * XScale, 200 * YScale, 400 * XScale , 400 * YScale);
//Get our edited bitmap into a region of the texture atlas
BitmapTextureAtlasSource source = new BitmapTextureAtlasSource(Bitmap_bg);
mBackground = BitmapTextureAtlasTextureRegionFactory.createFromSource(mBitmapBGTextureAtlas, source, 0, 0);
Bitmap_bg.recycle();
//Finally, create our background sprite with this new texture region
Sprite mBackgroundSprite = new Sprite(0, 0, mCamera.getWidth(), mCamera.getHeight(), mBackground);
mBackgroundSprite.setZIndex(1);
mScene.attachChild(mBackgroundSprite);
And the function cutSquareOutOfBitmap()
public static Bitmap cutSquareOutOfBitmap(Bitmap MyImage, float Xpos, float Ypos, float Width, float Height) {
Bitmap mBitmap = MyImage.copy(Bitmap.Config.ARGB_8888, true);
Paint mPaint = new Paint();
Canvas mCanvas = new Canvas(mBitmap );
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint .setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
mPaint .setColor(Color.TRANSPARENT);
mCanvas.drawBitmap(mBitmap , 0, 0, null);
mCanvas.drawRect(Xpos, Ypos, Xpos + Width, Ypos + Height, mPaint );
return mBitmap ;
}
If you run this - not a lot to look at but a big white square, however, this is a transparent region, the square is actually the background we set earlier.
To demonstrate how the contents will be obscured, you could create a scrollable area, as mentioned in my previous comment I wrote a small container class you are welcome to use,
Custom ScrollView in andengine
Underneath the first code block in this answer, after,
mScene.attachChild(mBackgroundSprite);
You could now add,
//Now we can use the ShapeScrollContainer just as an example so the user can
//scroll our container shapes around
//Create it around the same area as the cut out
ShapeScrollContainer mShapeScrollContainer = new ShapeScrollContainer(40, 200, 400, 400, new IShapeScrollContainerTouchListener() {
#Override
public void OnContentClicked(Shape pShape) {
// TODO Auto-generated method stub
//Add code here for content click event
}
});
//Disable the ShapeScrollContainer ability to change the visibility
//of contents - we no longer require this as the background will
//cover them outside of the bounds of the ShapeScrollContainer itself
mShapeScrollContainer.SetContentVisiblitiyControl(false);
//Disable alpha
mShapeScrollContainer.SetAlphaVisiblitiyControl(false);
//Allow user to scroll both horizontally and vertically
mShapeScrollContainer.SetScrollableDirections(true, true);
//Don't allow the user to scroll to no where
mShapeScrollContainer.SetScrollLock(true);
//Allow use to scroll half the container over in either direction
mShapeScrollContainer.SetScrollLockPadding(50.0f,50.0f);
//Attach the container to the scene and register the event listener
mScene.registerTouchArea(mShapeScrollContainer);
mScene.attachChild(mShapeScrollContainer);
//Finally add some content to the container, what ever extends Shape,
//Sprite, Animated Sprite, Text, ChangeableText e.t.c.
Rectangle mRectangle = new Rectangle(200, 360, 80, 80);
mRectangle.setColor(0.0f, 1.0f, 0.0f);
mRectangle.setZIndex(0);
//Attach to the scene and the ShapeScrollContainer
mScene.attachChild(mRectangle);
mShapeScrollContainer.Add(mRectangle);
Rectangle mRectangle2 = new Rectangle(40, 360, 80, 80);
mRectangle2.setColor(0.0f, 0.0f, 1.0f);
mRectangle2.setZIndex(0);
mScene.attachChild(mRectangle2);
mShapeScrollContainer.Add(mRectangle2);
Rectangle mRectangle3 = new Rectangle(360, 360, 80, 80);
mRectangle3.setColor(1.0f, 1.0f, 0.0f);
mRectangle3.setZIndex(0);
mScene.attachChild(mRectangle3);
mShapeScrollContainer.Add(mRectangle3);
//And sort the order in which shapes are rendered
mScene.sortChildren();
Now you should get something like the following after scrolling,
As another alternative if you are going for a simpler background you could forgo the bitmap manipulation and simply make the square with four surrounding rectangles making up the sides to the edge of the screen.
Or you could physically split your background into 4 surrounding rectangles and a central square with an image editor. Then create 5 sprites, set the z order of the four rectangles to 2, the square to 0 and any content sprites to 1.
Hope this is of use.