1

In my code I cannot draw a String at precise coordinates. Its upper left corner does not start at the given coordinates but somewhere else. However if I draw a rectangle from the same given coordinates it is well placed. How on earth can this behaviour be possible ?

Here is my code I call in the beforeShow() method :

Image photoBase = fetchResourceFile().getImage("Voiture_4_3.jpg");
    Image watermark = fetchResourceFile().getImage("Watermark.png");


    f.setLayout(new LayeredLayout());
    final Label drawing = new Label();
    f.addComponent(drawing);


    // Image mutable dans laquelle on va dessiner (fond blancpar défaut)
    Image mutableImage = Image.createImage(photoBase.getWidth(), photoBase.getHeight());

    // Paint all the stuff
    paintAll(mutableImage.getGraphics(), photoBase, watermark, photoBase.getWidth(), photoBase.getHeight());


    drawing.getUnselectedStyle().setBgImage(mutableImage);
    drawing.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);


    // Save the graphics
    // Save the image with the ImageIO class
    long time = new Date().getTime();
    OutputStream os;
    try {
        os = Storage.getInstance().createOutputStream("screenshot_" + Long.toString(time) + ".png");
        ImageIO.getImageIO().save(mutableImage, os, ImageIO.FORMAT_PNG, 1.0f);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

And the paintAll method

public void paintAll(Graphics g, Image background, Image watermark, int width, int height) {

    // Full quality
    float saveQuality = 1.0f;

    // Create image as buffer
    Image imageBuffer = Image.createImage(width, height, 0xffffff);
    // Create graphics out of image object
    Graphics imageGraphics  = imageBuffer.getGraphics();

    // Do your drawing operations on the graphics from the image
    imageGraphics.drawImage(background, 0, 0);
    imageGraphics.drawImage(watermark, 0, 0);

    imageGraphics.setColor(0xFF0000);

    // Upper left corner
    imageGraphics.fillRect(0, 0, 10, 10);

    // Lower right corner
    imageGraphics.setColor(0x00FF00);
    imageGraphics.fillRect(width - 10, height - 10, 10, 10);

    imageGraphics.setColor(0xFF0000);
    Font f = Font.createTrueTypeFont("Geometos", "Geometos.ttf").derive(220, Font.STYLE_BOLD);
    imageGraphics.setFont(f);
    // Draw a string right below the M from Mercedes on the car windscreen (measured in Gimp)
    int w = 0, h = 0;

    imageGraphics.drawString("HelloWorld", w, h);


    // Coin haut droit de la string
    imageGraphics.setColor(0x0000FF);
    imageGraphics.fillRect(w, h, 20, 20);

    // Draw the complete image on your Graphics object g (the screen I guess) 
    g.drawImage(imageBuffer, 0, 0);


}

Result for w = 0, h = 0 (no apparent offset) : no offset

Result for w = 841 , h = 610 (offset appears on both axis : there is an offset between the blue point near Mercedes M on the windscreen and the Hello World String) with offset

EDIT1: I also read this SO question for Android where it is advised to convert the dpi into pixel. Does it also applies in Codename One ? If so how can I do that ? I tried

Display.getInstance().convertToPixel(measureInMillimeterFromGimp)

without success (I used mm because the javadoc tells that dpi is roughly 1 mm)

Any help would be appreciated,

Cheers

Community
  • 1
  • 1
HelloWorld
  • 2,275
  • 18
  • 29

2 Answers2

1

Both g and imageGraphics are the same graphics created twice which might have some implications (not really sure)...

You also set the mutable image to the background of a style before you finished drawing it. I don't know if this will be the reason for the oddities you are seeing but I would suspect that code.

David Cohen
  • 429
  • 2
  • 4
  • imageGraphics is a trick to save the image in full resolution (see http://stackoverflow.com/a/37748864/6351897). I will change the suspicious part you pointed out! – HelloWorld Jun 13 '16 at 10:18
  • Unfortunatelly settiing the mutable image to the background after drawing it did not change anything (although it makes sense). Thanks anyway. I still cannot understand why the blue recatangle follows the coordinates but the string does not! – HelloWorld Jun 13 '16 at 10:25
  • Are these screenshots from the scaled mode in the simulator or from devices? Notice that some artifacts might occur if "scrollable" is unchecked in the simulator menu. – Shai Almog Jun 14 '16 at 04:17
  • This comes from the simulator. The example is based from CN1 Hello World GUI. So the form has scrollable Y enabled but X disabled. I tried to enable X without change. – HelloWorld Jun 14 '16 at 04:26
  • Pretty much all of the code relies on drawString() drawing in the right location as nothing would work if that didn't work correctly... You aren't running this in a separate thread or something like that? – Shai Almog Jun 15 '16 at 04:44
  • @Shai : version 115 of CN1 plugin fixed the issue which appeared only in the simulator (this was related to http://stackoverflow.com/questions/37986722/why-do-i-get-a-different-behviour-in-codename-one-simulator-than-on-a-real-andro) – HelloWorld Jun 24 '16 at 09:54
0

Inspired from Gabriel Hass' answer I finally made it work using another intermediate Image to only write the String at (0 ; 0) and then drawing this image on the the imageBuffer Image now at the right coordinates. It works but to my mind drawString(Image, Coordinates) should directly draw at the given coordinates, shouldn't it @Shai ?

String eventually at the righ coordinates (blue point expected to be on the top left corner of String HelloWorld

Here is the method paintAll I used to solve my problem (beforeShow code hasn't changed) :

    // Full quality
    float saveQuality = 1.0f;

    String mess = "HelloWorld";

    // Create image as buffer
    Image imageBuffer = Image.createImage(width, height, 0xffffff);
    // Create graphics out of image object
    Graphics imageGraphics  = imageBuffer.getGraphics();


    // Do your drawing operations on the graphics from the image
    imageGraphics.drawImage(background, 0, 0);
    imageGraphics.drawImage(watermark, 0, 0);

    imageGraphics.setColor(0xFF0000);

    // Upper left corner
    imageGraphics.fillRect(0, 0, 10, 10);

    // Lower right corner
    imageGraphics.setColor(0x00FF00);
    imageGraphics.fillRect(width - 10, height - 10, 10, 10);


    // Create an intermediate image just with the message string (will be moved to the right coordinates later)
    Font f = Font.createTrueTypeFont("Geometos", "Geometos.ttf").derive(150, Font.STYLE_BOLD);
    // Get the message dimensions 
    int messWidth = f.stringWidth(mess);
    int messHeight = f.getHeight();

    Image messageImageBuffer = Image.createImage(messWidth, messHeight, 0xffffff);
    Graphics messageImageGraphics  = messageImageBuffer.getGraphics();

    messageImageGraphics.setColor(0xFF0000);
    messageImageGraphics.setFont(f);

    // Write the string at (0; 0)
    messageImageGraphics.drawString(mess, 0, 0);

    // Move the string to its final location right below the M from Mercedes on the car windscreen (measured in Gimp) 
    int w = 841, h = 610;   
    imageGraphics.drawImage(messageImageBuffer, w, h);


    // This "point" is expected to be on the lower left corner of the M letter from Mercedes and on the upper left corner of the message string
    imageGraphics.setColor(0x0000FF);
    imageGraphics.fillRect(w, h, 20, 20);

    // Draw the complete image on your Graphics object g 
    g.drawImage(imageBuffer, 0, 0);
Community
  • 1
  • 1
HelloWorld
  • 2,275
  • 18
  • 29
  • It looks like this workaround may not be necessary anymore from CN1 lib version 115 onwards (see http://stackoverflow.com/questions/37986722/why-do-i-get-a-different-behviour-in-codename-one-simulator-than-on-a-real-andro for details). It was a simulator only issue indeed! – HelloWorld Jun 24 '16 at 09:51