Constraining the area of an image zoomed

edited August 2015 in Questions about Code

Here's my load image program so far. It loads images, resizes the window to either the image size or 90% of the display size (whichever is less), allows you to zoom in on the image or zoom out and allows you to drag images that are larger than the window. My problem is I would like the zoom to zoom in on the center of the image in the window. I want the current center pixel in the window to be the center pixel after the zoom. I can't figure out how to do it.

Here's my code so far:

/*  L or l loads a new image
    Z zooms in on the image
    z zoom out
    X or X zooms to original size
    Drag mouse to drag around zoomed image

 */


PImage img = null; 
boolean imageSelected = false;  
float zoom = 1.0;
float cX = 0;  //corner placement
float cY = 0;
float dX = 0.0; //dragged offset
float dY = 0.0;

int oX = 0; // mouse offset
int oY = 0;
boolean locked = false;

void setup() {
  frame.setResizable(true);
  size(600, 600);
  selectInput("Select a file to process:", "fileSelected");
} 

void draw() {
    background(100);
    if (!imageSelected) 
          ;
    else{
        cornerOffset();                      //process the location of the corner x,y
        image(img, cX, cY, img.width * zoom, img.height * zoom);
    }

} 

void fileSelected(File selection) {
  if (selection == null) 
    println("Window was closed or the user hit cancel.");
  else {
    img = loadImage( selection.getAbsolutePath());
    imageSelected = true;

    int h = img.height;                               //process the window size
    if(h > (int)((float) displayHeight * 0.9))
      h = (int)((float)displayHeight * 0.9);
    int w = img.width;
    if(w > (int)((float)displayWidth * 0.9))
         w = (int)((float)displayWidth * 0.9);

    frame.setSize(w,h);
  }
} 

void keyPressed() {
  if ((key == 'L') || (key == 'l')) {
    selectInput("Select a file to process:", "fileSelected");

  }
  else if (key =='Z'){

      if (zoom < 4.0){
         zoom = zoom+0.2;
         //dX = -(dX/2)-(img.width * zoom - width)/2; // here is my problem
                //how do I make sure that durning  the zoom, the current cent of the display remains the center?
        //dY = dY-((img.height * zoom) - img.height)/2;

      }
  }

  else if (key == 'z'){
      if(zoom > 0.2){
        zoom = zoom - 0.2;
        if(dX < width - img.width *zoom) 
          dX = width - img.width * zoom ;
         else if (dX >0)
            dX = 0;
         if(dY < height - img.height * zoom) 
            dY = height - img.height * zoom;
         else if (dY >0)
            dY = 0;
      }
  }      
  else if(key == 'X'||key =='x'){
       zoom = 1.0;
       dX =0;
       dY = 0;
  }

}
void cornerOffset(){
  if(img.width*zoom < width){            //center smaller image in window
    cX = ((width - img.width*zoom) / 2);
    dX = 0;
  }
  else cX = dX;

  if(img.height * zoom < height){  // center smaller image in window
    cY = ((height - img.height * zoom)/2);
    dY= 0;
  }
  else cY = dY;

}
void mousePressed() {
  locked = true;
  oX= mouseX; 
  oY=mouseY;

}
void mouseReleased() {
  locked = false;
}
void mouseDragged() {
  if(locked) {
    dX += mouseX-oX;
    dY += mouseY-oY; 
    if(dX < width - img.width *zoom) 
      dX = width - img.width * zoom ;  // constrain so image isn't pulled past its dimensions
     else if (dX >0)
      dX = 0;
   if(dY < height - img.height * zoom) 
      dY = height - img.height * zoom;
     else if (dY >0)
      dY = 0;
    oX = mouseX;
    oY = mouseY;
  }
}

Answers

  • edited August 2015

    I figured out the zoom thing ( I think). The program has gotten a lot larger and is more functional. I have a question. I have this written now to use a pen tablet. It wont draw with the mouse. If you want to try it out and you don't have a pen tablet of the tablet library, you're going to have to edit the code in the mouse functions to not use pen pressure. Is there a way I could fix this code to except input from either a mouse or a pen? Here's the program so far. Parts are still hard coded.

  • Part 1:

    import codeanticode.tablet.*;
    import javax.swing.*; 
    
    Tablet tablet;
    
    
    int numUndo = 10;
    int curUndo  = 0;
    int numLayers = 2;
    int undoInstances = 0;
    int redoInstances = 0;
    PImage img = null; 
    PGraphics []layers;
    PGraphics []uLayers;
    PGraphics temp;
    
    int curLayer = 0;
    boolean imageSelected = false; 
    float zoom = 1.0;
    float cX = 0;  //corner placement
    float cY = 0;
    float dX = 0.0; //dragged offset
    float dY = 0.0;
    float rdX = 0.0;
    float rdY = 0.0;
    float zX = 0;
    float zY = 0;
    int thickness = 10;
    int strength = 50;
    int oX = 0; // mouse offset
    int oY = 0;
    boolean locked = false;
    boolean dragging = false;
    boolean pickColor = false;
    boolean saveUndo = false;
    color aColor;
    color bColor;
    String info;
    void setup() {
    
      info = "Layer: " + curLayer + " Brushsize: " + thickness;
      frame.setTitle(info); 
      tablet = new Tablet(this);
      uLayers = new PGraphics[numUndo*numLayers];
      layers = new PGraphics[numLayers];
      frame.setResizable(true);
      size(600, 600);
    
    
      noFill();
    
      selectInput("Select a file to process:", "fileSelected");
    
    } 
    
    void draw() {
        background(100);
        if (!imageSelected) 
              ;
        else{
              layers[curLayer].beginDraw();
              layers[curLayer].endDraw();
              cornerOffset();                      //process the location of the corner x,y
              image(layers[curLayer], cX, cY, img.width * zoom, img.height * zoom);
            //  image(canvas,0,0);
        }
      ellipse(mouseX,mouseY,thickness*zoom,thickness*zoom);
      info = "Layer: " + curLayer + " Brushsize: " + thickness + " Strength: " + strength + " Zoom:" + zoom +" X: " + mouseX + " Y: "+ mouseY
                           + " dX: " + dX + " dY: " + dY + " rdX: " + rdX + " rdY: " + rdY;
      frame.setTitle(info); 
    } 
    
    void fileSelected(File selection) {
      if (selection == null) 
        println("Window was closed or the user hit cancel.");
      else {
        img = loadImage( selection.getAbsolutePath());
    
           layers[0] = createGraphics(img.width,img.height);
            layers[1] = createGraphics(img.width,img.height);
            temp = createGraphics(img.width,img.height);
            layers[0].beginDraw();
            layers[0].image(img,0,0);
          layers[0].endDraw();
            layers[1].beginDraw();
           layers[1].image(layers[0],0,0);
          layers[1].endDraw();
          for(int i= 0; i< numUndo * numLayers;i++){
          uLayers[i] = createGraphics(img.width,img.height);
             uLayers[i].beginDraw();
           uLayers[i].image(layers[0],10,10);
          uLayers[i].endDraw();
          temp.beginDraw();
          temp.background(127);
          temp.endDraw();
          }
    
    
        layers[0].beginDraw();
        layers[0].filter(POSTERIZE,12);
        layers[0].endDraw();
    
        layers[0].beginDraw();
        layers[1].beginDraw();
        layers[0].stroke(255,0,0);
        layers[1].stroke(0,0,255);
        layers[0].strokeWeight(thickness);
        layers[1].strokeWeight(thickness);
        layers[0].endDraw();
        layers[1].endDraw();
    
        imageSelected = true;
    
        int h = img.height;                               //process the window size
        if(h > (int)((float) displayHeight * 0.9))
          h = (int)((float)displayHeight * 0.9);
        int w = img.width;
        if(w > (int)((float)displayWidth * 0.9))
             w = (int)((float)displayWidth * 0.9);
    
        frame.setSize(w,h);
        zoom = 1.0;
        dX = dY = 0;
      }
    } 
    
  • Part 2:

    void keyPressed() {
      switch(key){
          case 'b':
          case 'B':
               selectInput("Select B image:", "load_B_image");
               break;
          case 's':
          case 'S':
               selectInput("SaveLayer", "save_layer");
               break;
          case 'L':
          case 'l':
              selectInput("Select a file to process:", "fileSelected");
              break;
          case 'Z': 
          case '+':  
              zoom_up(); 
              break;
          case 'z':
          case '-':
              zoom_down();
    
                 break;
           case 'X':
           case 'x':      
              zoom = 1.0;
              dX =0;
              dY = 0;
              zX = 0;
              zY = 0;
                 break;
           case ' ':
                 dragging = true;
                 cursor(MOVE);
                 break;
           case 'u':
           case 'U':
                undo();
                break;
           case 'r':
           case 'R':
                redo();
                break;
           case ']': thickness++;
                set_thickness();
                break;
           case '[': thickness--;
                  if(thickness<=0)
                    thickness = 1;
                set_thickness();
                break;
           case ';':
           case ':':
                if(strength <10) strength -= 1;
                     else strength -= (int)(strength *0.1);
                if(strength < 1) strength = 1;
                break;
           case '\'':
           case '\"':
               if(strength <10)strength+=1;
               else strength += (int)(strength * 0.1);
               if (strength > 100) strength = 100;
               break;
    
           case CODED:
                 switch(keyCode){
                       case UP:
                           if(curLayer < numLayers-1) curLayer++;
                           break;
                       case DOWN:
                           if(curLayer > 0) curLayer--;
                           break;
                       case ALT:
                           pickColor = true;
                           cursor(HAND);
                           break;
    
                 }
                 break;
    
      }
      info = "Layer: " + curLayer + " Brushsize: " + thickness + " Strength: " + strength +" X: " + mouseX + " Y: "+ mouseY;
      frame.setTitle(info); 
    
    }
    
    void keyReleased() {
      if(dragging){
        dragging = false;
        cursor(ARROW);
      }
      else if(pickColor){
        pickColor = false;
        cursor(ARROW);
    
      }
    }
    void cornerOffset(){
      cX = dX+zX;
      cY= dY+zY;
    
    
    
    }
    
  • Part 3:

    void mousePressed() {
    
      if(pickColor){
        float offsetX = dX+zX;
        float offsetY= dY+zY;  
       layers[0].beginDraw();
       layers[1].beginDraw();
       aColor = layers[0].get((int)((mouseX-offsetX)/zoom), (int)((mouseY-offsetY)/zoom));
        bColor = layers[1].get((int)((mouseX-offsetX)/zoom), (int)((mouseY-offsetY)/zoom));
        layers[0].stroke(aColor);
        layers[1].stroke(bColor);
        layers[0].endDraw();
        layers[1].endDraw();
      }
      else if(dragging){
      locked = true;
      oX= mouseX; 
      oY=mouseY;
      }
      else{
        save_undo();
        layers[0].beginDraw();
        layers[1].beginDraw();
        float offsetX = dX+zX;
        float offsetY= dY+zY;
        layers[0].stroke(aColor,strength*tablet.getPressure());
        layers[1].stroke(bColor,strength*tablet.getPressure());
        layers[0].line((mouseX-offsetX)/zoom, (mouseY-offsetY)/zoom, 
                      (mouseX-offsetX)/zoom, (mouseY-offsetY)/zoom);
        layers[1].line((mouseX-offsetX)/zoom, (mouseY-offsetY)/zoom, 
                      (mouseX-offsetX)/zoom, (mouseY-offsetY)/zoom);
        layers[0].endDraw();
        layers[1].endDraw();
      }
    
    
    }
    void mouseReleased() {
      locked = false;
      saveUndo = false;
    
    
    }
    
    void mouseDragged() {
      if(!dragging && !pickColor){
    
        layers[0].beginDraw();
        layers[1].beginDraw();
        layers[0].stroke(aColor,strength*tablet.getPressure());
        layers[1].stroke(bColor,strength*tablet.getPressure());
        layers[0].line((pmouseX-(dX+zX))/zoom, (pmouseY-(dY+zY))/zoom, 
                      (mouseX-(dX+zX))/zoom, (mouseY-(dY+zY))/zoom);
        layers[1].line((pmouseX-(dX+zX))/zoom, (pmouseY-(dY+zY))/zoom, 
                      (mouseX-(dX+zX))/zoom, (mouseY-(dY+zY))/zoom);
        layers[0].endDraw();
        layers[1].endDraw();
    
    
      }
      else if(locked && dragging) {
        dX += mouseX-oX;
        dY += mouseY-oY; 
        rdX= dX /zoom;
        rdY = dY / zoom;
    
        oX = mouseX;
        oY = mouseY;
      }
    }
    void undo(){
      if(undoInstances >0){
        println("undo instances= "+undoInstances+" CurUndo= "+curUndo);
        if(curUndo == 0)curUndo =numUndo; //wrap around
        for(int i = 0; i < numLayers; i++){
          println(i * numUndo+curUndo);
          layers[i].beginDraw();
          layers[i].endDraw(); //seems you need to set the pixels
          temp.beginDraw();
          temp.image(layers[i],0,0);
          temp.endDraw();
          layers[i].beginDraw();
          layers[i].image(uLayers[i*numUndo+curUndo-1],0,0);
          layers[i].endDraw();
          uLayers[i*numUndo+curUndo-1].beginDraw();
          uLayers[i*numUndo+curUndo-1].image(temp,0,0);
          uLayers[i*numUndo+curUndo-1].endDraw();
    
        }
    
         curUndo--;
         undoInstances--;
         redoInstances++;
      }
    }
    void redo(){
      if(redoInstances > 0){
    
        for(int i = 0; i < numLayers;i++){
          layers[i].beginDraw();
          layers[i].endDraw();
          temp.beginDraw();
          temp.image(layers[i],0,0);
          temp.endDraw();
          layers[i].beginDraw();
          layers[i].image(uLayers[i*numUndo+curUndo],0,0);
          layers[i].endDraw();
          uLayers[i*numUndo+curUndo].beginDraw();
          uLayers[i*numUndo+curUndo].image(temp,0,0);
          uLayers[i*numUndo+curUndo].endDraw();
         }
        curUndo++;
        undoInstances++;
        redoInstances--;
        if(curUndo == numUndo)
          curUndo = 0;
    
      }
    
    }
    
    void save_undo(){
         for(int i = 0; i < numLayers;i++){
              layers[i].beginDraw();
              layers[i].endDraw();          
              uLayers[i * numUndo +curUndo].beginDraw();
              uLayers[i * numUndo + curUndo].image(layers[i],0,0);
              uLayers[i * numUndo + curUndo].endDraw();
          }
          curUndo++;
          if(curUndo == numUndo) curUndo = 0;
          redoInstances = 0; 
          undoInstances++;
          if(undoInstances>numUndo)undoInstances = numUndo;
          println("finished drawing ", curUndo,undoInstances, redoInstances);    
    } 
    void set_thickness(){
      for(int i = 0; i < numLayers; i++){
            layers[i].beginDraw();   
            layers[i].strokeWeight(thickness); 
            layers[i].endDraw();
      }
    }
    void zoom_up(){
       if (zoom < 10.0){
         zoom = zoom+0.5;
         dX = rdX * zoom;
         dY = rdY * zoom;
         zX= (width - width * zoom)/2;
         zY = (height - height * zoom)/2;
    
        }
    
    }
    void zoom_down(){
       if(zoom > 0.5){
         zoom = zoom - 0.5;
         if(zoom < 0.5) zoom = 0.5;
         dX = rdX * zoom;
         dY = rdY * zoom;
         zX= (width - width * zoom)/2;
         zY = (height - height * zoom)/2;
    
    
       }
    //   dX=rdX * zoom;
    //   dY = rdY * zoom;
    }
    void load_B_image(File selection){
      if (selection == null) 
          ;
      else {
        img = loadImage( selection.getAbsolutePath());
        layers[curLayer].beginDraw();
        layers[curLayer].image(img,0,0);
        layers[curLayer].endDraw();
        curUndo = 0;
        undoInstances = 0;
        redoInstances = 0;
      }
    }
    void save_layer(File selection){
      String name= selection.getAbsolutePath();
      boolean save = false;
      if(selection.exists()){
          println("fileExist");
          try { 
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
           } 
          catch (Exception e) { 
               e.printStackTrace();
           } 
          String preset= name;
          String op1s = JOptionPane.showInputDialog(frame, "File Exists!! Replace?", preset);
          if(op1s != null) {
               save = true;
               name = op1s;
          }
      }
      if(save){
        layers[curLayer].beginDraw();
        layers[curLayer].save(name);
        layers[curLayer].endDraw();
    
      }
    
    }
    
Sign In or Register to comment.