Reputation: 668
I've been attempting to flip an image on a canvas. I would have flipped the entire context, but that would draw everything backwards and I'm only applying this to some images.
The images in question are the full size of the canvas which is where
WIDTH
and HEIGHT
come from.
The image flipping part of the function is here. Basically the image is
drawn to an off screen canvas (_buffer_ctx
) and then I use drawImage
to add it to the final scene.
// Load images and draw to _buffer_ctx
// ...
let img = this._buffer_ctx.getImageData( 0, 0, WIDTH, HEIGHT );
const IMG_WIDTH = img.width;
const IMG_HEIGHT = img.height;
const SCAN_WIDTH = IMG_WIDTH / 2;
let out = this._buffer_ctx.createImageData( IMG_WIDTH, IMG_HEIGHT );
const ELEMENTS_PER_PIXEL = 4;
for ( let y = 0; y < IMG_HEIGHT; ++y )
{
for ( let x = 0; x < SCAN_WIDTH; ++x )
{
let p_near = ( x + y * SCAN_WIDTH ) * ELEMENTS_PER_PIXEL;
let p_far = ( ( IMG_WIDTH - x ) + y * SCAN_WIDTH ) * ELEMENTS_PER_PIXEL;
for ( let e = 0; e < ELEMENTS_PER_PIXEL; ++e )
out.data[ p_far + e ] = img.data[ p_near + e ];
}
}
this._buffer_ctx.putImageData( out, 0, 0 );
// Use main_ctx.drawImage( _buffer_ctx, ... )
// ...
The problem I'm having is that only the top half of the image is being flipped.
Here are some images to demonstrate what I mean:
I had noticed that only half the image was being flipped, so I tried multiplying the height by two. This gets me the desired result.
const IMG_HEIGHT = img.height * 2; // Just this line.
This seems strange to me as the getImageData
function and the off screen canvas both use the unmultiplyed height. The off screen canvas is created using document.createElement
and it's width
and height
properties are set to the same values as the on screen one. The WIDTH
and HEIGHT
constants also gets their values from the same place.
I did at first think it was because the canvas scales to image down, but the width is also changed and yet that works unmultiplyed, so I'm having a hard time understanding why I only have to multiply the height value.
Upvotes: 1
Views: 761
Reputation: 668
After some messing around it looks like @AgataB was correct. I was using SCAN_WIDTH
to find the y
component of the pixel index.
There were also a couple of other problems with the code.
Here is the fixed version.
let img = this._buffer_ctx.getImageData( 0, 0, WIDTH, HEIGHT );
let out = this._buffer_ctx.createImageData( img );
const IMG_WIDTH = img.width;
const IMG_HEIGHT = img.height; // Don't need to multiply by two.
const SCAN_WIDTH = IMG_WIDTH / 2;
const ELEMENTS_PER_PIXEL = 4;
for ( let y = 0; y < IMG_HEIGHT; ++y )
{
let y_part = y * IMG_WIDTH;
// Use IMG_WIDTH instead of SCAN_WIDTH so that we get the correct
// y component. - @AgataB's comment.
for ( let x = 0; x < SCAN_WIDTH; ++x )
{
let x_near = x;
let x_far = ( IMG_WIDTH - ( x + 1 ) );
// When calculating the x component of the far pixel index we
// should add 1 to x. The array is 0 based.
let p_near = ( x_near + y_part ) * ELEMENTS_PER_PIXEL;
let p_far = ( x_far + y_part ) * ELEMENTS_PER_PIXEL;
for ( let e = 0; e < ELEMENTS_PER_PIXEL; ++e )
{
let near = p_near + e;
let far = p_far + e;
out.data[ far ] = img.data[ near ];
out.data[ near ] = img.data[ far ];
// Make sure that we set the left pixels of the output
// image. This was why only half the image was being drawn
// when I tried what @AgataB said.
}
}
Upvotes: 1