Pages

Monday, April 05, 2010

CDK-JChemPaint #1: rendering molecules

I reported earlier that the CDK-JChemPaint patch is now a clean add-on from the CDK releases. This means that you download cdk-1.3.4.jar and cdk-jchempaint-8.jar separately, put them in your class path, and get started with, for example, Groovy:
$ export CLASSPATH=cdk-1.3.4.jar:cdk-jchempaint-8.jar
$ groovy renderMol.groovy

I have tuned to code in this tutorial by Gilleain a bit, resulting in this code:
import java.util.List;

import java.awt.*;
import java.awt.image.*;

import javax.imageio.*;

import org.openscience.cdk.*;
import org.openscience.cdk.interfaces.*;
import org.openscience.cdk.layout.*;
import org.openscience.cdk.renderer.*;
import org.openscience.cdk.renderer.font.*;
import org.openscience.cdk.renderer.generators.*;
import org.openscience.cdk.renderer.visitor.*;
import org.openscience.cdk.templates.*;

int WIDTH = 600;
int HEIGHT = 600;

// the draw area and the image should be the same size
Rectangle drawArea = new Rectangle(WIDTH, HEIGHT);
Image image = new BufferedImage(
  WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB
);

IMolecule triazole = MoleculeFactory.make123Triazole();
StructureDiagramGenerator sdg = new StructureDiagramGenerator();
sdg.setMolecule(triazole);
sdg.generateCoordinates();
triazole = sdg.getMolecule();

// generators make the image elements
List generators = new ArrayList();
generators.add(new BasicSceneGenerator());
generators.add(new BasicBondGenerator());
generators.add(new BasicAtomGenerator());

// the renderer needs to have a toolkit-specific font manager
AtomContainerRenderer renderer =
  new AtomContainerRenderer(generators, new AWTFontManager());

// the call to 'setup' only needs to be done on the first paint
renderer.setup(triazole, drawArea);

// paint the background
Graphics2D g2 = (Graphics2D)image.getGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, WIDTH, HEIGHT);

// the paint method also needs a toolkit-specific renderer
renderer.paint(triazole, new AWTDrawVisitor(g2));

ImageIO.write((RenderedImage)image, "PNG", new File("triazole.png"));

9 comments:

  1. Thank you Egon for your article. With your help I was able to render the molecule. I also tried to do it with the help of tutorial by Gilleain but I could not manage to do that. I used cdk v.1.2.4 and cdk-jchemaint-15 and Java could not load BasicBondGenerator class.

    ReplyDelete
  2. Dear Паша Мусієнко,

    please download CDK 1.3.5. You need the 1.3.x series instead of the 1.2.x series you tried.

    I hope that helps.

    ReplyDelete
  3. I actually did. I have downloaded CDK 1.3.4. It helped. :)

    ReplyDelete
  4. Dear Egon, I am trying now to render the molecules with adjustable dimensions. In your example they are fixed - 600x600 px.
    I would appreciate any information of yours on how to do it. Thanks in advance.
    Paul.

    ReplyDelete
  5. I have managed to render molecules with canvas adjustable to molecules dimensions. These tutorials helped me - Renderer Tutorial-Molecule Table and Renderer Tutorial-Editing a molecule
    I don't know if someone it might help but the following is the code snippet from this article a bit reworked


    import java.util.List;

    import java.awt.*;
    import java.awt.image.*;

    import javax.imageio.*;

    import org.openscience.cdk.*;
    import org.openscience.cdk.interfaces.*;
    import org.openscience.cdk.layout.*;
    import org.openscience.cdk.renderer.*;
    import org.openscience.cdk.renderer.font.*;
    import org.openscience.cdk.renderer.generators.*;
    import org.openscience.cdk.renderer.visitor.*;
    import org.openscience.cdk.templates.*;

    int WIDTH = 1;
    int HEIGHT = 1;

    // the draw area and the image should be the same size
    Rectangle drawArea = new Rectangle(0, 0, WIDTH, HEIGHT);


    IMolecule triazole = MoleculeFactory.make123Triazole();
    StructureDiagramGenerator sdg = new StructureDiagramGenerator();
    sdg.setMolecule(triazole);
    try {
    sdg.generateCoordinates();
    } catch (Exception ex) {}
    triazole = sdg.getMolecule();

    // generators make the image elements
    List generators = new ArrayList();
    generators.add(new BasicSceneGenerator());
    generators.add(new BasicBondGenerator());
    generators.add(new BasicAtomGenerator());

    // the renderer needs to have a toolkit-specific font manager
    AtomContainerRenderer renderer =
    new AtomContainerRenderer(generators, new AWTFontManager());

    // the call to 'setup' only needs to be done on the first paint
    renderer.setup(triazole, drawArea);

    Rectangle diagramRectangle = renderer.calculateDiagramBounds(triazole);
    Rectangle result = renderer.shift(drawArea, diagramRectangle);

    HEIGHT = (int) (result.getHeight() + result.y);
    WIDTH = (int) (result.getWidth() + result.x);

    // paint the background
    Image image = new BufferedImage(
    WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB
    );
    Graphics2D g2 = (Graphics2D)image.getGraphics();
    g2.setColor(Color.WHITE);
    g2.fillRect(0, 0, WIDTH, HEIGHT);

    // the paint method also needs a toolkit-specific renderer
    renderer.paint(triazole, new AWTDrawVisitor(g2));

    ImageIO.write((RenderedImage)image, "PNG", new File("triazole.png"));

    ReplyDelete
  6. Happy to hear you got it worked out. I'm quite busy right now; finishing some stuff with deadlines today.

    You should start a blog :) Thanx for the code snippet; I'm sure others will find it useful too!

    ReplyDelete
  7. Thanks, Egon! In its time maybe I will start one. For now I am a newbie in java.
    Thanks again and let your code run smoothly :)

    ReplyDelete
  8. Thanks for the post, these code snippets are really useful.

    ReplyDelete