Package com.alibaba.simpleimage.jai.scale

Source Code of com.alibaba.simpleimage.jai.scale.LanczosOpImage

/*
* Copyright 1999-2101 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.simpleimage.jai.scale;

import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.util.Map;

import javax.media.jai.GeometricOpImage;
import javax.media.jai.ImageLayout;
import javax.media.jai.RasterAccessor;
import javax.media.jai.RasterFormatTag;

import com.alibaba.simpleimage.util.ImageUtils;

/**
* 由于存在分块导致缩略后图片有问题,所以暂时放弃利用JAI实现Lanczos的想法,
* lanczos算法在LanczosScaleOp中实现
* @author wendell
*/
@Deprecated
@SuppressWarnings("unchecked")
public class LanczosOpImage extends GeometricOpImage {

  private static final double WORK_LOAD_FACTOR = 0.265;

  protected double scaleX;
  protected double scaleY;
  protected double scaleFactor;
  protected int destWidth;
  protected int destHeight;
  protected LanczosResizeFilter filter;
  protected Rectangle filterRect;

  protected int xTrans;
  protected int yTrans;
 
  public LanczosOpImage(RenderedImage source, ImageLayout layout, Map config,
      double scaleX, double scaleY) {
    super(vectorize(source), layoutHelper(source, scaleX, scaleY, layout),
        config, true, // cobbleSources,
        null, // BorderExtender
        new InterpolationLanczos(), null);

    this.scaleX = scaleX;
    this.scaleY = scaleY;

    this.destWidth = (int) (source.getWidth() * scaleX);
    this.destHeight = (int) (source.getHeight() * scaleY);
    if (destWidth <= 0) {
      destWidth = 1;
    }
    if (destHeight <= 0) {
      destHeight = 1;
    }

    this.filter = new LanczosResizeFilter();
    int bandsNum = source.getColorModel().getNumComponents();
    if (bandsNum != 3) {
      throw new IllegalArgumentException("Not supported");
    }

    this.scaleFactor = this.scaleX * this.scaleY;
    if (scaleFactor > WORK_LOAD_FACTOR) {
      filterRect = new Rectangle(destWidth, source.getHeight());
    } else {
      filterRect = new Rectangle(source.getWidth(), destHeight);
    }
  }

  private static ImageLayout layoutHelper(RenderedImage source,
      double scaleX, double scaleY, ImageLayout il) {
    ImageLayout layout = (il == null) ? new ImageLayout()
        : (ImageLayout) il.clone();

    if (scaleX <= 0.0 || scaleY <= 0.0) {
      throw new IllegalArgumentException("Illegal scaleX or scaleY value");
    }

    int dWidth = (int) (source.getWidth() * scaleX);
    if (dWidth <= 0) {
      dWidth = 1;
    }
    int dHeight = (int) (source.getHeight() * scaleY);
    if (dHeight <= 0) {
      dHeight = 1;
    }

    layout.setMinX((int) Math.floor(source.getMinX() * scaleX));
    layout.setMinY((int) Math.floor(source.getMinY() * scaleY));
    layout.setWidth(dWidth);
    layout.setHeight(dHeight);

    return layout;
  }
 
  protected Rectangle backwardMapRect(Rectangle destRect, int sourceIndex) {
    double scale = Math.max(1.0 / scaleX, 1.0);
    double support = scale * filter.getSupport() * filter.getBlur();

    if (support < 0.5) {
      support = 0.5;
    }
    // (int) (start - center) + (int) center
    Rectangle srcRect = getSourceImage(sourceIndex).getBounds();
   
    double center = (destRect.x + 0.5) / scaleX;
    double t1 = center - support + 0.5;
    double t2 = center + support + 0.5;
    int start = (int) (t1 > 0 ? t1 : 0);
    int stop = (int) (t2 < (srcRect.width) ? t2 : srcRect.width);
    int startX = (int)(start - center) + (int)center;
   
//    int startX = (int)center;
    if (startX < 0) {
      startX = 0;
    }
    xTrans = (int)(center) - startX;

    center = (destRect.x + destRect.getWidth() - 1 + 0.5) / scaleX;
    t1 = center - support + 0.5;
    t2 = center + support + 0.5;
    // int endX = (int) (center + support + 0.5);
    start = (int) (t1 > 0 ? t1 : 0);
    stop = (int) (t2 < (srcRect.width) ? t2 : srcRect.width);
    int endX = stop;
//    int endX = (int)center;

    scale = Math.max(1.0 / scaleY, 1.0);
    support = scale * filter.getSupport() * filter.getBlur();

    if (support < 0.5) {
      support = 0.5;
    }
    // int startY = (int) ((destRect.getY() + 0.5) / scaleY - support +
    // 0.5);
    center = (destRect.y + 0.5) / scaleY;
    t1 = center - support + 0.5;
    start = (int) (t1 > 0 ? t1 : 0);
    int startY = (int)(start - center) + (int)center;
//    int startY = (int)center;
    if (startY < 0) {
      startY = 0;
    }
    yTrans = (int)center - startY;
    // int endY = (int) ((destRect.getY() + destRect.getHeight() - 1 + 0.5)
    // / scaleY + support + 0.5);
    center = (destRect.getY() + destRect.getHeight() - 1 + 0.5) / scaleY;
    t1 = center - support + 0.5;
    t2 = center + support + 0.5;
    start = (int) (t1 > 0 ? t1 : 0);
    stop = (int) (t2 < (srcRect.getHeight()) ? t2 : srcRect.getHeight());
    int endY = stop;
//    int endY = (int)center;
   
    Rectangle mapRect = new Rectangle(startX, startY, endX - startX + 1, endY
        - startY + 1);

    return mapRect.intersection(srcRect);
  }

  protected Rectangle forwardMapRect(Rectangle sourceRect, int sourceIndex) {
    return null;
  }

  protected Rectangle mapHorizontalComputeRect(Rectangle srcRect, Rectangle destRect) {
    return new Rectangle(destRect.x, srcRect.y, destRect.width, srcRect.height);
  }
 
  protected Rectangle mapVerticalComputeRect(Rectangle srcRect, Rectangle destRect) {
    return new Rectangle(srcRect.x, destRect.y, srcRect.width, destRect.height);
  }
 
  protected void computeRect(Raster[] sources, WritableRaster dest,
      Rectangle destRect) {
    RasterFormatTag[] formatTags = getFormatTags();
    RasterAccessor dst = new RasterAccessor(dest, destRect, formatTags[1],
        getColorModel());

    Rectangle mapRect = backwardMapRect(destRect, 0);
    Rectangle tmpRect = null;
    if (scaleFactor > WORK_LOAD_FACTOR) {
      tmpRect = mapHorizontalComputeRect(mapRect, destRect).intersection(
          filterRect);
    } else {
      tmpRect = mapVerticalComputeRect(mapRect, destRect).intersection(filterRect);
    }

    SampleModel nsm = dest.getSampleModel().createCompatibleSampleModel(
        tmpRect.width, tmpRect.height);
    WritableRaster filterRaster = Raster.createWritableRaster(nsm,
        tmpRect.getLocation());
    RasterAccessor f = new RasterAccessor(filterRaster, tmpRect,
        formatTags[1], getColorModel());

    RasterAccessor src = new RasterAccessor(sources[0],
        mapRect.intersection(sources[0].getBounds()), formatTags[0],
        getSourceImage(0).getColorModel());

    switch (dst.getDataType()) {
    case DataBuffer.TYPE_BYTE:
      computeRectByte(src, f, dst);
      break;
    case DataBuffer.TYPE_USHORT:
      computeRectUShort(src, f, dst);
      break;
    case DataBuffer.TYPE_SHORT:
      computeRectShort(src, f, dst);
      break;
    case DataBuffer.TYPE_INT:
      computeRectInt(src, f, dst);
      break;
    case DataBuffer.TYPE_FLOAT:
      computeRectFloat(src, f, dst);
      break;
    case DataBuffer.TYPE_DOUBLE:
      computeRectDouble(src, f, dst);
      break;
    default:
      throw new UnsupportedOperationException("Not implemented yet");
    }

    if (dst.isDataCopy()) {
      dst.clampDataArrays();
      dst.copyDataToRaster();
    }
  }

  private void computeRectByte(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if (scaleFactor > WORK_LOAD_FACTOR) {
      lanczosHorizontalFilterByte(src, mid);
      lanczosVerticalFilterByte(mid, dst);
    } else {
      lanczosVerticalFilterByte(src, mid);
      lanczosHorizontalFilterByte(mid, dst);
    }
  }

  private void computeRectUShort(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if ((scaleX * scaleY) > WORK_LOAD_FACTOR) {
      // lanczosHorizontalFilterUShort(src, mid);
      // lanczosVerticalFilterUShort(mid, dst);
    } else {
      // lanczosVerticalFilterUShort(src, mid);
      // lanczosHorizontalFilterUShort(mid, dst);
    }
  }

  private void computeRectShort(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if ((scaleX * scaleY) > WORK_LOAD_FACTOR) {
      // lanczosHorizontalFilterShort(src, mid);
      // lanczosVerticalFilterShort(mid, dst);
    } else {
      // lanczosVerticalFilterShort(src, mid);
      // lanczosHorizontalFilterShort(mid, dst);
    }
  }

  private void computeRectInt(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if ((scaleX * scaleY) > WORK_LOAD_FACTOR) {
      // lanczosHorizontalFilterInt(src, mid);
      // lanczosVerticalFilterInt(mid, dst);
    } else {
      // lanczosVerticalFilterInt(src, mid);
      // lanczosHorizontalFilterInt(mid, dst);
    }
  }

  private void computeRectFloat(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if ((scaleX * scaleY) > WORK_LOAD_FACTOR) {
      // lanczosHorizontalFilterFloat(src, mid);
      // lanczosVerticalFilterFloat(mid, dst);
    } else {
      // lanczosVerticalFilterFloat(src, mid);
      // lanczosHorizontalFilterFloat(mid, dst);
    }
  }

  private void computeRectDouble(RasterAccessor src, RasterAccessor mid,
      RasterAccessor dst) {
    if ((scaleX * scaleY) > WORK_LOAD_FACTOR) {
      // lanczosHorizontalFilterDouble(src, mid);
      // lanczosVerticalFilterDouble(mid, dst);
    } else {
      // lanczosVerticalFilterDouble(src, mid);
      // lanczosHorizontalFilterDouble(mid, dst);
    }
  }

  private void lanczosHorizontalFilterByte(RasterAccessor src,
      RasterAccessor dst) {
    double scale = Math.max(1.0 / scaleX, 1.0);
    double support = scale * filter.getSupport() * filter.getBlur();

    if (support < 0.5) {
      support = 0.5;
      scale = 1.0;
    }

    byte[][] srcDataArrays = src.getByteDataArrays();
    byte[][] dstDataArrays = dst.getByteDataArrays();
    double pixel[] = { 0, 0, 0, 0 };
    final int channel = src.getNumBands();
    scale = 1.0 / scale;

    int contributionsNum = (int) (2.0 * support + 3.0);
    LanczosContributionInfo contribution[] = new LanczosContributionInfo[contributionsNum];
    for (int t = 0; t < contributionsNum; t++) {
      contribution[t] = new LanczosContributionInfo();
    }

    double center, t1, t2, density;
    int start, stop, n;
    final int dstWidth = dst.getWidth(), dstHeight = dst.getHeight();
    final int srcWidth = src.getWidth();
    final int dstScanlineStride = dst.getScanlineStride();
    final int srcScanlineStride = src.getScanlineStride();

    for (int x = 0; x < dstWidth; x++) {
      /*
       * Get the location of the piexls that will be used to compute new
       * pixel
       */
      center = (x + 0.5) / scaleX + xTrans;
      t1 = center - support + 0.5;
      t2 = center + support + 0.5;
      start = (int) (t1 > 0 ? t1 : 0);
      stop = (int) (t2 < (srcWidth) ? t2 : srcWidth);
      density = 0.0;

      for (n = 0; n < (stop - start); n++) {
        contribution[n].pixel = start + n;
        contribution[n].weight = getLanczosResizeFilterWeight(scale
            * ((double) (start + n) - center + 0.5));
        density += contribution[n].weight;
      }
      if ((density != 0.0) && (density != 1.0)) {
        density = 1.0 / density;
        for (int i = 0; i < n; i++) {
          contribution[i].weight *= density;
        }
      }
     
      int tmp3 = x * channel;
      //TODO test
      int tmp5 = ((int) (start - center) + (int) center) * channel + xTrans * channel;
//      int tmp5 = start * channel;

      /* Start compute new piexl */
      for (int y = 0; y < dstHeight; y++) {
        pixel[0] = 0.0;
        pixel[1] = 0.0;
        pixel[2] = 0.0;
        pixel[3] = 0.0;

        int tmp6 = tmp5;
        for (int i = 0; i < n; i++) {
          // if(channel == 3) {
          pixel[0] += (srcDataArrays[0][tmp6++] & 0xFF)
              * contribution[i].weight;
          pixel[1] += (srcDataArrays[1][tmp6++] & 0xFF)
              * contribution[i].weight;
          pixel[2] += (srcDataArrays[2][tmp6++] & 0xFF)
              * contribution[i].weight;
          // } else if(channel == 1) {
          // pixel[0] += (srcDataArrays[0][tmp6++] & 0xFF) *
          // contribution[i].weight;
          // } else {
          // pixel[0] += (srcDataArrays[0][tmp6++] & 0xFF) *
          // contribution[i].weight;
          // pixel[1] += (srcDataArrays[1][tmp6++] & 0xFF) *
          // contribution[i].weight;
          // pixel[2] += (srcDataArrays[2][tmp6++] & 0xFF) *
          // contribution[i].weight;
          // pixel[3] += (srcDataArrays[3][tmp6] & 0xFF) *
          // contribution[i].weight;
          // }
        }

        int tmp4 = tmp3;
        // if(channel == 3) {
        dstDataArrays[0][tmp4++] = ImageUtils.clampRoundByte(pixel[0]);
        dstDataArrays[1][tmp4++] = ImageUtils.clampRoundByte(pixel[1]);
        dstDataArrays[2][tmp4] = ImageUtils.clampRoundByte(pixel[2]);
        // } else if(channel == 1) {
        // dstDataArrays[0][tmp3] = ImageUtils.clampRoundByte(pixel[0]);
        // } else {
        // dstDataArrays[0][tmp4++] =
        // ImageUtils.clampRoundByte(pixel[0]);
        // dstDataArrays[1][tmp4++] =
        // ImageUtils.clampRoundByte(pixel[1]);
        // dstDataArrays[2][tmp4++] =
        // ImageUtils.clampRoundByte(pixel[2]);
        // dstDataArrays[3][tmp4] = ImageUtils.clampRoundByte(pixel[3]);
        // }

        tmp3 += dstScanlineStride;
        tmp5 += srcScanlineStride;
      }
    }
  }

  private void lanczosVerticalFilterByte(RasterAccessor src,
      RasterAccessor dst) {
    double scale = Math.max(1.0 / scaleY, 1.0);
    double support = scale * filter.getSupport() * filter.getBlur();

    if (support < 0.5) {
      support = 0.5;
      scale = 1.0;
    }

    /* Get memory of filter array */
    scale = 1.0 / scale;
    byte[][] srcDataArrays = src.getByteDataArrays();
    byte[][] dstDataArrays = dst.getByteDataArrays();
    double pixel[] = { 0, 0, 0, 0 };
    final int channel = dst.getNumBands();

    int contributionNums = (int) (2.0 * support + 3.0);
    LanczosContributionInfo contribution[] = new LanczosContributionInfo[contributionNums];
    for (int t = 0; t < contributionNums; t++) {
      contribution[t] = new LanczosContributionInfo();
    }

    double center, t1, t2, density;
    int start, stop, n;
    final int dstHeight = dst.getHeight(), dstWidth = dst.getWidth();
    final int srcHeight = src.getHeight();
    final int srcScanlineStride = src.getScanlineStride();
    final int dstScanlineStride = dst.getScanlineStride();

    /* First, we compute rows pixel, then compute columns pixel */
    for (int y = 0; y < dstHeight; y++) {
      /*
       * Get the location of the piexls that will be used to compute new
       * pixel
       */
      center = (y + 0.5) / scaleY;
      t1 = center - support + 0.5;
      t2 = center + support + 0.5;
      start = (int) (t1 > 0 ? t1 : 0);
      stop = (int) (t2 < (srcHeight) ? t2 : srcHeight);
      density = 0.0;
      /* Get the value of Sinc */
      for (n = 0; n < (stop - start); n++) {
        contribution[n].pixel = start + n;
        contribution[n].weight = getLanczosResizeFilterWeight(scale
            * ((double) (start + n) - center + 0.5));
        density += contribution[n].weight;
      }
      if ((density != 0.0) && (density != 1.0)) {
        density = 1.0 / density;
        for (int i = 0; i < n; i++) {
          contribution[i].weight *= density;
        }
      }

      int tmp3 = y * dstScanlineStride;
      int tmp5 = ((int) (center)) * srcScanlineStride
          + ((int) (start - center)) * srcScanlineStride + yTrans * srcScanlineStride;
//      int tmp5 = start * srcScanlineStride;

      /* Start compute new piexl */
      for (int x = 0; x < dstWidth; x++) {
        pixel[0] = 0.0;
        pixel[1] = 0.0;
        pixel[2] = 0.0;
        pixel[3] = 0.0;

        int tmp6 = tmp5;
        for (int i = 0; i < n; i++) {
          int tmp7 = tmp6;
          // if(channel == 3) {
          pixel[0] += (srcDataArrays[0][tmp7++] & 0xFF)
              * contribution[i].weight;
          pixel[1] += (srcDataArrays[1][tmp7++] & 0xFF)
              * contribution[i].weight;
          pixel[2] += (srcDataArrays[2][tmp7] & 0xFF)
              * contribution[i].weight;
          // } else if(channel == 1) {
          // pixel[0] += (srcDataArrays[0][tmp7] & 0xFF) *
          // contribution[i].weight;
          // } else {
          // pixel[0] += (srcDataArrays[0][tmp7++] & 0xFF) *
          // contribution[i].weight;
          // pixel[1] += (srcDataArrays[1][tmp7++] & 0xFF) *
          // contribution[i].weight;
          // pixel[2] += (srcDataArrays[2][tmp7++] & 0xFF) *
          // contribution[i].weight;
          // pixel[3] += (srcDataArrays[3][tmp7] & 0xFF) *
          // contribution[i].weight;
          // }
          tmp6 += srcScanlineStride;
        }

        // if(channel == 3) {
        dstDataArrays[0][tmp3++] = ImageUtils.clampRoundByte(pixel[0]);
        dstDataArrays[1][tmp3++] = ImageUtils.clampRoundByte(pixel[1]);
        dstDataArrays[2][tmp3++] = ImageUtils.clampRoundByte(pixel[2]);
        // } else if(channel == 1) {
        // dstDataArrays[0][tmp3++] =
        // ImageUtils.clampRoundByte(pixel[0]);
        // } else {
        // dstDataArrays[0][tmp3++] =
        // ImageUtils.clampRoundByte(pixel[0]);
        // dstDataArrays[1][tmp3++] =
        // ImageUtils.clampRoundByte(pixel[1]);
        // dstDataArrays[2][tmp3++] =
        // ImageUtils.clampRoundByte(pixel[2]);
        // dstDataArrays[3][tmp3++] =
        // ImageUtils.clampRoundByte(pixel[3]);
        // }

        tmp5 += channel;
      }
    }
  }

  private double getLanczosResizeFilterWeight(final double x) {
    double blur;
    double scale;

    blur = Math.abs(x) / filter.getBlur();
    scale = filter.getScale() / filter.getWindowSupport();
    scale = filter.window(blur * scale);

    return scale * filter.filter(blur);
  }
TOP

Related Classes of com.alibaba.simpleimage.jai.scale.LanczosOpImage

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.