avm2: Implement BitmapData.getPixels()

This commit is contained in:
Nathan Adams 2023-02-05 23:01:00 +01:00
parent 25cc6f3243
commit dff558170e
7 changed files with 154 additions and 2 deletions

View File

@ -3,7 +3,9 @@
use crate::avm2::activation::Activation;
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{bitmapdata_allocator, BitmapDataObject, Object, TObject};
use crate::avm2::object::{
bitmapdata_allocator, BitmapDataObject, ByteArrayObject, Object, TObject,
};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
@ -318,6 +320,40 @@ pub fn copy_pixels<'gc>(
Ok(Value::Undefined)
}
/// Implements `BitmapData.getPixels`.
pub fn get_pixels<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(bitmap_data) = this.and_then(|t| t.as_bitmap_data()) {
bitmap_data.read().check_valid(activation)?;
let rectangle = args
.get(0)
.unwrap_or(&Value::Undefined)
.coerce_to_object(activation)?;
let x = rectangle
.get_property(&Multiname::public("x"), activation)?
.coerce_to_i32(activation)?;
let y = rectangle
.get_property(&Multiname::public("y"), activation)?
.coerce_to_i32(activation)?;
let width = rectangle
.get_property(&Multiname::public("width"), activation)?
.coerce_to_i32(activation)?;
let height = rectangle
.get_property(&Multiname::public("height"), activation)?
.coerce_to_i32(activation)?;
let bytearray = ByteArrayObject::from_storage(
activation,
bitmap_data.read().get_pixels(x, y, width, height)?,
)?;
return Ok(bytearray.into());
}
Ok(Value::Undefined)
}
/// Implements `BitmapData.getPixel`.
pub fn get_pixel<'gc>(
activation: &mut Activation<'_, 'gc>,
@ -1241,6 +1277,7 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>
write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES);
const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[
("getPixels", get_pixels),
("getPixel", get_pixel),
("getPixel32", get_pixel32),
("setPixel", set_pixel),

View File

@ -1,4 +1,4 @@
use crate::avm2::{Object as Avm2Object, Value as Avm2Value};
use crate::avm2::{Error, Object as Avm2Object, Value as Avm2Value};
use crate::bitmap::turbulence::Turbulence;
use crate::context::RenderContext;
use crate::context::UpdateContext;
@ -334,6 +334,7 @@ mod wrapper {
}
}
use crate::avm2::bytearray::ByteArrayStorage;
pub use wrapper::BitmapDataWrapper;
impl fmt::Debug for BitmapData<'_> {
@ -511,6 +512,30 @@ impl<'gc> BitmapData<'gc> {
}
}
pub fn get_pixels(
&self,
x: i32,
y: i32,
width: i32,
height: i32,
) -> Result<ByteArrayStorage, Error<'gc>> {
let mut result = ByteArrayStorage::new();
let x0 = x.max(0) as u32;
let y0 = y.max(0) as u32;
let x1 = (x + width).clamp(0, self.width as i32) as u32;
let y1 = (y + height).clamp(0, self.height as i32) as u32;
for y in y0..y1 {
for x in x0..x1 {
let color = self.pixels[(x + y * self.width) as usize];
result.write_int(color.to_un_multiplied_alpha().0)?;
}
}
Ok(result)
}
pub fn set_pixel(&mut self, x: u32, y: u32, color: Color) {
let current_alpha = self.get_pixel_raw(x, y).map(|p| p.alpha()).unwrap_or(0);
self.set_pixel32(x as i32, y as i32, color.with_alpha(current_alpha));

View File

@ -0,0 +1,49 @@
package {
import flash.display.DisplayObjectContainer;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
public class Test {
static var WIDTH: uint = 10;
static var HEIGHT: uint = 10;
public static function run(container: DisplayObjectContainer) {
var src: BitmapData = createSource();
printPixels(src, 0, 0, 5, 5);
printPixels(src, 5, 5, 3, 3);
printPixels(src, 0, 0, 10, 10);
printPixels(src, -1, -1, 2, 2);
}
static function createSource(): BitmapData {
var src: BitmapData = new BitmapData(WIDTH, HEIGHT, true, 0x00000000);
src.noise(0);
return src;
}
static function printPixels(src: BitmapData, x: int, y: int, width: uint, height: uint): void {
var rect: Rectangle = new Rectangle(x, y, width, height);
var pixels: ByteArray = src.getPixels(rect);
trace("/// var pixels = getPixels(new Rectangle(" + x + ", " + y + ", " + width + ", " + height + "))");
trace("// pixels.length");
trace(pixels.length);
trace("");
trace("// pixels.position");
trace(pixels.position);
trace("");
trace("// pixels");
var result = [];
pixels.position = 0;
for (var i = 0; i < pixels.length; i++) {
result.push(pixels.readUnsignedByte());
}
trace(result);
trace("");
}
}
}

View File

@ -0,0 +1,40 @@
/// var pixels = getPixels(new Rectangle(0, 0, 5, 5))
// pixels.length
100
// pixels.position
100
// pixels
255,167,241,217,255,42,130,200,255,216,254,67,255,77,152,85,255,140,226,179,255,153,146,72,255,51,98,65,255,243,13,35,255,229,95,48,255,209,200,237,255,42,202,229,255,72,233,197,255,241,176,196,255,21,138,229,255,155,77,57,255,108,195,81,255,226,32,174,255,12,225,6,255,152,109,97,255,255,52,161,255,68,85,122,255,200,171,80,255,201,178,222,255,178,246,181,255,226,76,79
/// var pixels = getPixels(new Rectangle(5, 5, 3, 3))
// pixels.length
36
// pixels.position
36
// pixels
255,134,156,196,255,46,54,42,255,2,115,18,255,238,154,235,255,215,24,204,255,79,162,124,255,127,242,179,255,140,109,72,255,208,30,72
/// var pixels = getPixels(new Rectangle(0, 0, 10, 10))
// pixels.length
400
// pixels.position
400
// pixels
255,167,241,217,255,42,130,200,255,216,254,67,255,77,152,85,255,140,226,179,255,71,23,17,255,152,84,47,255,17,45,5,255,88,245,107,255,214,136,7,255,153,146,72,255,51,98,65,255,243,13,35,255,229,95,48,255,209,200,237,255,97,12,75,255,2,53,57,255,129,132,184,255,20,162,156,255,180,90,103,255,42,202,229,255,72,233,197,255,241,176,196,255,21,138,229,255,155,77,57,255,246,247,232,255,161,5,211,255,254,237,165,255,213,243,217,255,228,91,250,255,108,195,81,255,226,32,174,255,12,225,6,255,152,109,97,255,255,52,161,255,30,25,253,255,54,80,233,255,183,129,143,255,195,58,30,255,15,192,44,255,68,85,122,255,200,171,80,255,201,178,222,255,178,246,181,255,226,76,79,255,221,159,136,255,103,189,206,255,31,242,97,255,0,142,120,255,151,151,14,255,52,98,7,255,215,94,71,255,161,88,41,255,142,91,162,255,245,98,70,255,134,156,196,255,46,54,42,255,2,115,18,255,100,230,6,255,135,239,83,255,9,209,8,255,83,79,81,255,248,101,143,255,180,240,128,255,183,203,25,255,238,154,235,255,215,24,204,255,79,162,124,255,140,55,223,255,193,173,165,255,209,51,209,255,58,190,3,255,240,33,233,255,177,183,140,255,203,216,47,255,127,242,179,255,140,109,72,255,208,30,72,255,27,45,79,255,175,113,113,255,128,95,215,255,242,211,158,255,244,196,241,255,155,148,150,255,232,29,171,255,129,147,179,255,115,126,27,255,39,217,196,255,57,87,22,255,100,65,185,255,53,21,232,255,240,60,149,255,216,232,206,255,30,24,100,255,250,173,104,255,221,252,89,255,50,19,1,255,9,57,11,255,15,31,229,255,202,113,104
/// var pixels = getPixels(new Rectangle(-1, -1, 2, 2))
// pixels.length
4
// pixels.position
4
// pixels
255,167,241,217

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
num_frames = 1