44import com .annimon .ownlang .lib .*;
55import java .awt .Dimension ;
66import java .lang .reflect .Modifier ;
7+ import java .nio .IntBuffer ;
78import java .util .Arrays ;
89import java .util .HashMap ;
910import java .util .Map ;
1819import javafx .scene .canvas .Canvas ;
1920import javafx .scene .canvas .GraphicsContext ;
2021import javafx .scene .effect .*;
22+ import javafx .scene .image .Image ;
23+ import javafx .scene .image .PixelReader ;
24+ import javafx .scene .image .PixelWriter ;
25+ import javafx .scene .image .WritableImage ;
26+ import javafx .scene .image .WritablePixelFormat ;
2127import javafx .scene .input .DragEvent ;
2228import javafx .scene .input .KeyCode ;
2329import javafx .scene .input .KeyEvent ;
@@ -117,6 +123,7 @@ public void init() {
117123
118124 Functions .set ("addEventFilter" , new addEventFilter ());
119125 Functions .set ("addEventHandler" , new addEventHandler ());
126+ Functions .set ("createImage" , new createImage ());
120127
121128 final MapValue arcType = new MapValue (ArcType .values ().length );
122129 for (ArcType value : ArcType .values ()) {
@@ -571,6 +578,83 @@ public Value execute(Value... args) {
571578 }
572579//</editor-fold>
573580
581+ private static class ImageFXValue extends MapValue {
582+
583+ private final Image image ;
584+
585+ public ImageFXValue (Image image ) {
586+ super (8 );
587+ this .image = image ;
588+ init ();
589+ }
590+
591+ private void init () {
592+ set (new StringValue ("width" ), NumberValue .of (image .getWidth ()));
593+ set (new StringValue ("height" ), NumberValue .of (image .getHeight ()));
594+ set (new StringValue ("preserveRatio" ), NumberValue .fromBoolean (image .isPreserveRatio ()));
595+ set (new StringValue ("smooth" ), NumberValue .fromBoolean (image .isSmooth ()));
596+ set (new StringValue ("getPixels" ), new FunctionValue (this ::getPixels ));
597+ }
598+
599+ private Value getPixels (Value ... args ) {
600+ final int w = (int ) image .getWidth ();
601+ final int h = (int ) image .getHeight ();
602+ final int size = w * h ;
603+ final PixelReader pr = image .getPixelReader ();
604+ final WritablePixelFormat <IntBuffer > format = WritablePixelFormat .getIntArgbInstance ();
605+ final int [] buffer = new int [size ];
606+ pr .getPixels (0 , 0 , w , h , format , buffer , 0 , w );
607+
608+ final ArrayValue result = new ArrayValue (size );
609+ for (int i = 0 ; i < size ; i ++) {
610+ result .set (i , NumberValue .of (buffer [i ]));
611+ }
612+ return result ;
613+ }
614+
615+ @ Override
616+ public String toString () {
617+ return "JavaFX Image " + image ;
618+ }
619+ }
620+
621+ private static class createImage implements Function {
622+
623+ @ Override
624+ public Value execute (Value ... args ) {
625+ Arguments .checkAtLeast (1 , args .length );
626+ final Image result ;
627+ switch (args .length ) {
628+ case 1 :
629+ // createImage(url)
630+ result = new Image (args [0 ].asString ());
631+ break ;
632+ case 2 :
633+ default :
634+ // createImage(width, height)
635+ result = new WritableImage (args [0 ].asInt (), args [1 ].asInt ());
636+ break ;
637+ case 3 :
638+ // createImage(w, h, pixels)
639+ final int w = args [0 ].asInt ();
640+ final int h = args [1 ].asInt ();
641+ final int size = w * h ;
642+ final WritableImage writableImage = new WritableImage (w , h );
643+ final PixelWriter pw = writableImage .getPixelWriter ();
644+ final WritablePixelFormat <IntBuffer > format = WritablePixelFormat .getIntArgbInstance ();
645+ final int [] buffer = new int [size ];
646+ final ArrayValue array = (ArrayValue ) args [2 ];
647+ for (int i = 0 ; i < size ; i ++) {
648+ buffer [i ] = array .get (i ).asInt ();
649+ }
650+ pw .setPixels (0 , 0 , w , h , format , buffer , 0 , w );
651+ result = writableImage ;
652+
653+ }
654+ return new ImageFXValue (result );
655+ }
656+ }
657+
574658 public static class GraphicsFXValue extends MapValue {
575659
576660 private final GraphicsContext graphics ;
@@ -592,6 +676,7 @@ private void init() {
592676 functions .put ("clearRect" , this ::clearRect );
593677 functions .put ("clip" , this ::clip );
594678 functions .put ("closePath" , this ::closePath );
679+ functions .put ("drawImage" , this ::drawImage );
595680 functions .put ("fill" , this ::fill );
596681 functions .put ("fillArc" , this ::fillArc );
597682 functions .put ("fillOval" , this ::fillOval );
@@ -706,6 +791,36 @@ public Value closePath(Value... args) {
706791 return NumberValue .ZERO ;
707792 }
708793
794+ public Value drawImage (Value ... args ) {
795+ Arguments .checkAtLeast (3 , args .length );
796+ if (!(args [0 ] instanceof ImageFXValue )) {
797+ throw new TypeException ("ImageFX expected" );
798+ }
799+ final Image image = ((ImageFXValue ) args [0 ]).image ;
800+
801+ if (args .length >= 9 ) {
802+ graphics .drawImage (image ,
803+ args [1 ].asNumber (), args [2 ].asNumber (),
804+ args [3 ].asNumber (), args [4 ].asNumber (),
805+ args [5 ].asNumber (), args [6 ].asNumber (),
806+ args [7 ].asNumber (), args [8 ].asNumber ()
807+ );
808+ return NumberValue .ZERO ;
809+ }
810+
811+ if (args .length >= 5 ) {
812+ // x y w h
813+ graphics .drawImage (image ,
814+ args [1 ].asNumber (), args [2 ].asNumber (),
815+ args [3 ].asNumber (), args [4 ].asNumber ()
816+ );
817+ return NumberValue .ZERO ;
818+ }
819+
820+ graphics .drawImage (image , args [1 ].asNumber (), args [2 ].asNumber ());
821+ return NumberValue .ZERO ;
822+ }
823+
709824 public Value fill (Value ... args ) {
710825 graphics .fill ();
711826 return NumberValue .ZERO ;
0 commit comments