Package magick4j.effects

Source Code of magick4j.effects.ShadeEffect

package magick4j.effects;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import magick4j.Constants;
import magick4j.MagickImage;
import magick4j.PixelPacket;
import magick4j.exceptions.OptionException;

import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.toRadians;

/**
*
* @author serabe
*/
public class ShadeEffect extends BasicEffect{

  private boolean shading;
  private double azimuth;
  private double elevation;

  public ShadeEffect(boolean shading, double azimuth, double elevation){
    this.shading = shading;
    this.azimuth = azimuth;
    this.elevation = elevation;
  }

  @Override
  protected MagickImage effect(MagickImage image) throws OptionException {
    double[] light = this.calculateLightVector();

    BufferedImage orig = image.getImageToConvolve(3);
    MagickImage dst = image.createCompatible();

    int h = image.getHeight(), w = image.getWidth();
    int cw = w +2;
    int lcw = cw*4;
    int base;

    double distance, normalDistance, shade;
    double[] normal = new double[3];

    double[][] p = new double[3][lcw];
    double[] q = new double[w*4];
    double[][] s = new double[3][cw];

    WritableRaster o = orig.getRaster();
    WritableRaster d = dst.getImage().getRaster();

    p[1] = o.getPixels(0, 0, cw, 1, p[1]);
    p[2] = o.getPixels(0, 1, cw, 1, p[2]);

    for(int i = 0; i < cw; i++){
      base = 4*i;
      s[1][i] = PixelPacket.calculateIntensity(p[1], base);
      s[2][i] = PixelPacket.calculateIntensity(p[2], base);
    }

    for(int y = 0; y < h; y++){

      // Slide the p array.
      System.arraycopy(p[1], 0, p[0], 0, lcw);
      System.arraycopy(p[2], 0, p[1], 0, lcw);
      p[2] = o.getPixels(0, y+2, cw, 1, p[2]);

      // Slide the s array.
      System.arraycopy(s[1], 0, s[0], 0, cw);
      System.arraycopy(s[2], 0, s[1], 0, cw);
      for(int i = 0; i < cw; i++){
        base = 4*i;
        s[2][i] = PixelPacket.calculateIntensity(p[2], base);
      }

      normal[2] = 2.0*Constants.QuantumRange;

      for(int x = 0; x < w; x++){
        normal[0] = s[0][x]+s[1][x]+s[2][x]-s[0][x+2]-s[1][x+2]-s[2][x+2];
        normal[1] = s[2][x]+s[2][x+1]+s[2][x+2]-s[0][x]-s[0][x+1]-s[0][x+2];

        if(normal[0] == 0.0 && normal[1] == 0.0)
          shade = light[2];
        else{
          shade = 0.0;
          distance = normal[0]*light[0]+normal[1]*light[1]+normal[2]*light[2];

          if(distance > Constants.MagickEpsilon){
            normalDistance = normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2];
            if(normalDistance > Constants.MagickEpsilon*Constants.MagickEpsilon)
              shade = distance/sqrt(normalDistance);
          }
        }
        base = x*4;
        if(this.shading){
          q[base+0] = shade;
          q[base+1] = shade;
          q[base+2] = shade;
        }else{
          q[base+0] = roundToQuantum(Constants.QuantumScale*shade*p[1][base+4+0]);
          q[base+1] = roundToQuantum(Constants.QuantumScale*shade*p[1][base+4+1]);
          q[base+2] = roundToQuantum(Constants.QuantumScale*shade*p[1][base+4+2]);
        }

        q[base+3] = p[1][base+4+3];
      }

      d.setPixels(0, y, w, 1, q);

    }

    return dst;
  }

  protected double[] calculateLightVector(){
    double azimuthRadians = toRadians(this.azimuth);
    double elevationRadians = toRadians(this.elevation);

    double[] light = new double[3];

    light[0] = Constants.QuantumRange*cos(azimuthRadians)*cos(elevationRadians);
    light[1] = Constants.QuantumRange*sin(azimuthRadians)*cos(elevationRadians);
    light[2] = Constants.QuantumRange*sin(elevationRadians);

    return light;
  }
}
TOP

Related Classes of magick4j.effects.ShadeEffect

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.