Clip image to screen size on iOS port

50 views
Skip to first unread message

Adalbert

unread,
Feb 24, 2016, 6:45:36 AM2/24/16
to CodenameOne Discussions

After last iOS port update the image processing is clipped to screen size.
I don't know why there is ng.applyClip() in IOSImplementation.drawImage
If my screen width is 640 and I draw on image 1880 width drawing appeared only on left 640 points :(

For now my workaround is to comment line UIRectClip(CGRectMake(x, y, width, height)) in function CodenameOne_GLViewController .Java_com_codename1_impl_ios_IOSImplementation_setNativeClippingMutableImpl

To find out this bug it takes me a few days because working on iOS port is not easy. Huge part of port is written in Java and after crosscompiling it is “hashed”. Why you need java api level on native port? It make port not only hart to debug but most of all working slower.
For example to make the clip from core java code iOS port need 9 function level – only one in object C. I think that is the main cause that futures like animation is not working as fast as it should.




 

Shai Almog

unread,
Feb 24, 2016, 11:07:45 PM2/24/16
to CodenameOne Discussions
I have no idea what you are talking about. As far as I can tell nothing changed in that regard since 2014 or 2012 really.

It's possible you were working with the old pipeline (pre-OpenGL ES 2.x) which we deprecated a couple of years ago and blocked a while back since it was buggy and caused a lot of regressions.

Rewriting the entirety of the port in C would be a herculean task that won't necessarily provide the necessary advantages. Keep in mind that Java is GC'd and we can leverage our GC logic from the translated C code. Since we translate the code to C it is pretty fast and by improving our translation VM the port gets faster without any additional work from us.

Keeping most of the Codename One code in Java helps the porting/maintenance effort even for developers who aren't versed in C or native iOS development.

Adalbert

unread,
Feb 25, 2016, 10:04:12 AM2/25/16
to CodenameOne Discussions
I am talking about clip image to screen size in current iOS port.
I use source code generated by CN1 server so how can I use old pipeline?
In code built in the same way from 10-2015 there was no such problem.

Here is the code:
    public static Image scaleImageRGB(Image aImage, final int newWidth, final int newHight) {
        Image ii = Image.createImage(newWidth, newHight, 0);
        final Graphics g = ii.getGraphics();
        T.callSeriallyAndWaitisEDT(new Runnable() {
            public void run() {
                g.drawImage(aImage, 0, 0, newWidth, newHight);
            }
        });
        return ii;
    }

When you scale to dimension bigger than current screen resolution your scaled image will be clipped to screen dimension.

You were changing many thing in image processing but how I wrote it is hurt to debug crosscompiled java code for iOS port. May be you can do it on Java level? I can't.

Shai Almog

unread,
Feb 25, 2016, 11:46:48 PM2/25/16
to CodenameOne Discussions
You can use the old pipeline thru build hints (e.g. async paint).
The main limiting factor for image sizes is the GPU space, we limit overly large images to prevent the image from appearing blank. This has been in the code for ages so my only guess is that you used the old pipeline. If you changed that behavior (and I still have no idea what you changed) then you made a big mistake as this will fail on some devices.

Adalbert

unread,
Feb 26, 2016, 1:25:12 AM2/26/16
to CodenameOne Discussions
How can you explain that comment clipping code in CN1 port solve problem?

For now my workaround is to comment line UIRectClip(CGRectMake(x, y, width, height)) in function CodenameOne_GLViewController .Java_com_codename1_impl_ios_IOSImplementation_setNativeClippingMutableImpl

GPU limits for iPhone6 is 4096 points not 640 points!!!

So for sure bug is in CN1 port.

How I remember you have made many changes connected with charts.
For example drawing code were:

void Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl
(int color, int alpha, int x, int y, int width, int height) {
    //NSLog(@"Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl started");
    [UIColorFromRGB(color, alpha) set];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextStrokeRect(context, CGRectMake(x, y, width, height));
    //NSLog(@"Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl finished");
}
and now is:
void Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl
(int color, int alpha, int x, int y, int width, int height) {
    //NSLog(@"Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl started");
    [UIColorFromRGB(color, alpha) set];
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (currentMutableTransformSet) {
        CGContextSaveGState(context);
        CGContextConcatCTM(context, currentMutableTransform);
    }
    CGContextStrokeRect(context, CGRectMake(x, y, width, height));
    if (currentMutableTransformSet) {
        CGContextRestoreGState(context);
    }
    //NSLog(@"Java_com_codename1_impl_ios_IOSImplementation_nativeDrawRectMutableImpl finished");
}

Any tips how to debug java part of iOS port? Debug crosscompiled code on XCode is only way?

Shai Almog

unread,
Feb 26, 2016, 11:55:06 PM2/26/16
to CodenameOne Discussions
Which comment from where from when by whom?
I'm still trying to guess what you are talking about and that's probably a mistake. If you think you found something somewhere please provide links for information on that.

We made a lot of changes to the iOS port but not too many to the specific clip method. We currently debug with xcode but I'm not sure you should.

I think you should start from the beginning with a test case in Java that doesn't work. If you also have links to specific files/commits that you think are wrong feel free to add that. Right now I still have no idea what you are talking about.

Adalbert

unread,
Mar 6, 2016, 4:29:30 AM3/6/16
to CodenameOne Discussions

Below there is a test case (it use theme from CN1 project creator - Get Started App).
Here is print screen from iPhone6:

Second duke image is clipped to screen size (750x1334). The big image size is 2130x1800 - much less than GPU limits (4096).
After comment line UIRectClip(CGRectMake(x, y, width, height)) in function CodenameOne_GLViewController .Java_com_codename1_impl_ios_IOSImplementation_setNativeClippingMutableImpl the second image is not clipped.

But I think that root cause is in IOSImplementation.java NativeImage class:
        public NativeGraphics getGraphics() {
           
if(child == null) {
                child
= new NativeGraphics();
                child
.associatedImage = this;
           
}
           
return child;
       
}

After create NativeGraphics the clip should be setup to image size or GPU limits and than call applyClip().

P.S. I hope now everything is clear.


package eu.forann.issuetester;

import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Label;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.layouts.LayeredLayout;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;

public class IssueTester {

   
private Form current;
   
private Resources theme;

   
public void init(Object context) {
        theme
= UIManager.initFirstTheme("/theme");

       
// Pro only feature, uncomment if you have a pro subscription
       
// Log.bindCrashProtection(true);
   
}
       
public static void callSeriallyAndWaitisEDT(Runnable aRun) {
       
if (Display.getInstance().isEdt()) {
            aRun
.run();
       
} else {
           
Display.getInstance().callSeriallyAndWait(aRun);

       
}
   
}
   
public static Image scaleImageRGB(Image aImage, final int newWidth, final int newHight) {
       
Image ii = Image.createImage(newWidth, newHight, 0);
       
final Graphics g = ii.getGraphics();

        callSeriallyAndWaitisEDT
(new Runnable() {
           
public void run() {
                g
.drawImage(aImage, 0, 0, newWidth, newHight);
           
}
       
});
       
return ii;
   
}

   
public void start() {
       
if(current != null){
            current
.show();
           
return;
       
}
       
Form hi = new Form("Clip on iOS issue", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE));
               
Image image=theme.getImage("duke-no-logos.png");
               
Image bigImage=scaleImageRGB(image, image.getWidth()*10    , image.getHeight()*10);
               
Image littleImage=scaleImageRGB(bigImage, image.getWidth(), image.getHeight());
        hi
.addComponent(BorderLayout.CENTER,
               
LayeredLayout.encloseIn(
                       
BoxLayout.encloseY(
                                                           
new Label(image),
                               
new Label(littleImage)
 
//                               ,new Label(bigImage)
                       
)
                   
)
       
);
       
        hi
.show();
   
}

   
public void stop() {
        current
= Display.getInstance().getCurrent();
   
}
   
   
public void destroy() {
   
}

}



Shai Almog

unread,
Mar 6, 2016, 11:01:02 PM3/6/16
to CodenameOne Discussions
That's clearer but I still don't see the issue.

Setting the clip to the image size would be incorrect as we use -1 for a special case of no clip and in that case no clipping is applied as far as I can see from the code. Since you don't invoke any clip call there shouldn't be a clip further down the line.

Your testcase is overly complex so it's hard to see what is really going on. Using the callSeriallyAndWait logic seems totally redundant as all calls here are thru the EDT. You also used API's such as CENTER_BEHAVIOR_CENTER_ABSOLUTE from our original demo code which is a far more likely reason for things appearing cropped. I tried a simplified version and it worked just fine:

        Form hi = new Form("Duke", new BoxLayout(BoxLayout.Y_AXIS));
        Image im = Image.createImage(duke.getWidth() * 4, duke.getHeight() * 4, 0);
        im.getGraphics().drawImage(duke, 0, 0, duke.getWidth() * 4, duke.getHeight() * 4);
        hi.add(im);


Duke in this case is the icon image which is 512x512. Using 10x in this case did cross the gpu limit.

Steve CN1 Hannah

unread,
Mar 7, 2016, 1:01:18 PM3/7/16
to codenameone...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to codenameone-discu...@googlegroups.com.
Visit this group at https://groups.google.com/group/codenameone-discussions.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/e4a88114-0479-45eb-b2a6-c00764e37784%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Steve Hannah
Software Developer
Codename One
Reply all
Reply to author
Forward
0 new messages