2013-03-21 14 views
12

Witam Mam obraz kodu QR i chcę go zmienić, kiedy próbuję zmienić jego rozmiar na mały obraz przy użyciu tego kodu, zawsze otrzymuję obraz blury, a kod QR nie jest już ważny, gdy go skanuję , ale to działa dobrze, gdy zmiana rozmiaru do wielkości dużych obrazów z tego samego kodu:Jak zmienić rozmiar obrazu w Java?

public BufferedImage getScaledInstance(BufferedImage img, 
            int targetWidth, 
            int targetHeight, 
            Object hint, 
            boolean higherQuality) 
{ 
int type = (img.getTransparency() == Transparency.OPAQUE) ? 
    BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; 
BufferedImage ret = (BufferedImage)img; 
int w, h; 
if (higherQuality) { 
    // Use multi-step technique: start with original size, then 
    // scale down in multiple passes with drawImage() 
    // until the target size is reached 
    w = img.getWidth(); 
    h = img.getHeight(); 
} else { 
    // Use one-step technique: scale directly from original 
    // size to target size with a single drawImage() call 
    w = targetWidth; 
    h = targetHeight; 
} 

do { 
    if (higherQuality && w > targetWidth) { 
     w /= 2; 
     if (w < targetWidth) { 
      w = targetWidth; 
     } 
    } 

    if (higherQuality && h > targetHeight) { 
     h /= 2; 
     if (h < targetHeight) { 
      h = targetHeight; 
     } 
    } 

    BufferedImage tmp = new BufferedImage(w, h, type); 
    Graphics2D g2 = tmp.createGraphics(); 
    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); 
    //  g2.setRenderingHint(RenderingHints.KEY_DITHERING, hint); 
    g2.drawImage(ret, 0, 0, w, h, null); 
    g2.dispose(); 

    ret = tmp; 
} while (w != targetWidth || h != targetHeight); 

return ret; 
} 

co jest problemem, nie dokładnie zrozumieć, proszę mi dać przynajmniej podpowiedź, dziękuję

+0

Nie pokazałeś najważniejszego szczegółu - jaka podpowiedź interpunkcji ustawiasz! –

+0

wielkie dzięki, moja podpowiedź interpolacyjna to RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, próbowałem z wszystkimi możliwymi wartościami, nadal nie działał – Walllzzz

Odpowiedz

23

używam przekształcenie afiniczne do osiągnięcia tego zadania, tutaj jest mój kod, nadzieję, że pomoże

/** 
* scale image 
* 
* @param sbi image to scale 
* @param imageType type of image 
* @param dWidth width of destination image 
* @param dHeight height of destination image 
* @param fWidth x-factor for transformation/scaling 
* @param fHeight y-factor for transformation/scaling 
* @return scaled image 
*/ 
public static BufferedImage scale(BufferedImage sbi, int imageType, int dWidth, int dHeight, double fWidth, double fHeight) { 
    BufferedImage dbi = null; 
    if(sbi != null) { 
     dbi = new BufferedImage(dWidth, dHeight, imageType); 
     Graphics2D g = dbi.createGraphics(); 
     AffineTransform at = AffineTransform.getScaleInstance(fWidth, fHeight); 
     g.drawRenderedImage(sbi, at); 
    } 
    return dbi; 
} 
+0

Wielkie dzięki, że działa, ale koleś, co umieścić w fWidth i fHeight ?, za każdym razem otrzymuję inny wynik – Walllzzz

+1

to są współczynniki skali dla współrzędnych na osi X i Y patrz [javadoc] (http: // docs. oracle.com/javase/6/docs/api/java/awt/geom/AffineTransform.html#getScaleInstance%28double,%20double%29). na przykład, jeśli chcesz uzyskać wynikowy obraz 'połowa' duży jak oryginalny, przepuść' 0,5' dla obu wartości fWidth i fHeight. Wartości mniejsze niż "1" zostaną zmniejszone, wartości większe niż "1" zostaną zwiększone, "1" spowoduje obraz o tych samych wymiarach. – A4L

+0

Dzięki temu rozwiązałem mój problem, wybiorę to jako zaakceptowaną odpowiedź, ale wszystkie odpowiedzi są akceptowane – Walllzzz

7

Napisałem tę klasę, którą również osobiście używam. Mam nadzieję, że kodeks jest prosty.

import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Toolkit; 
import java.awt.image.BufferedImage; 
import java.awt.image.CropImageFilter; 
import java.awt.image.FilteredImageSource; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.ImageIcon; 
import javax.swing.JComponent; 


public class ImageScaler { 

     private ImageIcon originalImage; 
     private ImageIcon scaledImage; 

     public ImageScaler(Image image) { 
       this.originalImage = new ImageIcon(image); 
     } 

     public ImageScaler(String fileName) { 
       originalImage = new ImageIcon(fileName); 
     } 

     public void createScaledImage(int size, ScalingDirection scalingDirection) { 
       if (scalingDirection == ScalingDirection.HORIZONTAL) { 
         scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(size, -1, Image.SCALE_SMOOTH)); 
       } else { 
         scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(-1, size, Image.SCALE_SMOOTH)); 
       }  
     } 

     public void createScaledImage(int size, ScalingDirection scalingDirection, int scale) { 
       if (scalingDirection == ScalingDirection.HORIZONTAL) { 
         scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(size, -1, scale)); 
       } else { 
         scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(-1, size, scale)); 
       } 
     } 

     public void createScaledImage(int width, int height, ScaleType scaleType) { 
       int imageWidth = originalImage.getImage().getWidth(null); 
       int imageHeight = originalImage.getImage().getHeight(null); 
       double originalImageRatio = imageWidth/(double) imageHeight; 
       double scaledImageRatio = width/(double) height; 

       if(scaleType == ScaleType.FIT) { 
         if(imageHeight - (Math.abs(imageWidth - width)/originalImageRatio) <= height) { 
           scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(width, -1, Image.SCALE_SMOOTH)); 
         } else if(imageWidth - (Math.abs(imageHeight - height) * originalImageRatio) <= width) { 
           scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(-1, height, Image.SCALE_SMOOTH)); 
         } 
       } else if(scaleType == ScaleType.FILL) { 
         if(imageHeight - (Math.abs(imageWidth - width)/originalImageRatio) >= height) { 
           scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(width, -1, Image.SCALE_SMOOTH)); 
           int thumbHeight = scaledImage.getImage().getHeight(null); 

           // Crop the image 
           scaledImage = new ImageIcon(Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(scaledImage.getImage().getSource(), new CropImageFilter(0, (thumbHeight-height)/2, width, height)))); 
         } else if(imageWidth - (Math.abs(imageHeight - height) * originalImageRatio) >= width) { 
           scaledImage = new ImageIcon(originalImage.getImage().getScaledInstance(-1, height, Image.SCALE_SMOOTH)); 
           int thumbWidth = scaledImage.getImage().getWidth(null); 

           // Crop the image 
           scaledImage = new ImageIcon(Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(scaledImage.getImage().getSource(), new CropImageFilter((thumbWidth-width)/2, 0, width, height)))); 
         }    
       } 
     } 

     public void saveScaledImage(File file, ImageType imageType) { 
       if (scaledImage != null) { 
         BufferedImage bi = new BufferedImage(scaledImage.getIconWidth(), scaledImage.getIconHeight(), BufferedImage.TYPE_INT_RGB); 
         Graphics g = bi.getGraphics(); 
         g.drawImage(scaledImage.getImage(), 0, 0, null); 
         try { 
           ImageIO.write(bi, imageType.value(), file); 
         } catch (IOException ioe) { 
           System.out.println("Error occured saving scaled image"); 
         } 
       } else { 
         System.out.println("Scaled image has not yet been created"); 
       } 
     } 

     public void saveOriginalImage(File file, ImageType imageType) { 
       if (originalImage != null) { 
         BufferedImage bi = new BufferedImage(originalImage.getIconWidth(), originalImage.getIconHeight(), BufferedImage.TYPE_INT_RGB); 
         Graphics g = bi.getGraphics(); 
         g.drawImage(originalImage.getImage(), 0, 0, null); 
         try { 
           ImageIO.write(bi, imageType.value(), file); 
         } catch (IOException ioe) { 
           System.out.println("Error occured saving original image"); 
         } 
       } else { 
         System.out.println("Original image has not yet been created"); 
       } 
     } 

     // ENUMS 
     public enum ScalingDirection {VERTICAL, HORIZONTAL}; 
     public enum ScaleType {FIT, FILL}; 
     public enum ImageType { 
       IMAGE_JPEG ("jpeg"), 
       IMAGE_JPG ("jpg"), 
       IMAGE_PNG ("png"); 

       private String value = null; 

       ImageType(String value) { 
         this.value = value; 
       } 

       String value() { 
         return value; 
       } 
     }; 
} 
+0

Dziękuję, nie próbowałem, ponieważ powyższy kod zadziałał, niech inni spróbują. – Walllzzz

1
public static BufferedImage resizeImg(BufferedImage img, int newW, int newH) 
    { 
    int w = img.getWidth(); 
    int h = img.getHeight(); 
    BufferedImage dimg = new BufferedImage(newW, newH, img.getType()); 
    Graphics2D g = dimg.createGraphics(); 
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
      RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
    g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null); 
    g.dispose(); 
    return dimg;  
    } 
+1

Należy podać więcej informacji o tym, jak ten kod rozwiązuje problem PO. Nie jest jasne, w jaki sposób ten kod pomaga. – aravind

5

podstawie @ A4L za odpowiedź:

Bardziej straigt wersji naprzód. Również jego rozwiązanie skalowało tylko płótno, a nie sam obraz.

public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight) { 
     BufferedImage scaledImage = null; 
     if (imageToScale != null) { 
      scaledImage = new BufferedImage(dWidth, dHeight, imageToScale.getType()); 
      Graphics2D graphics2D = scaledImage.createGraphics(); 
      graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null); 
      graphics2D.dispose(); 
     } 
     return scaledImage; 
    } 

celu polepszenia jakości można dodać

graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
+0

Prostota jest genialna. Dziękuję Ci. – Apostolos

+0

Jedną ze strategii zwiększania jakości może być robienie tego w kilku małych krokach, dopóki nie zostanie osiągnięty pożądany pożądany rozmiar. – A4L

+0

Prawda, zwana "Progressive Scaling" - wyjaśniam to tutaj: http://stackoverflow.com/questions/24745147/java-resize-image- bez -zmiany-quality/36367652#36367652 na podstawie blogu Campbella: https: // community.oracle.com/docs/DOC-983611 – for3st

0

W rzeczywistości rozwiązanie jest jeszcze bardziej prosta. Nie musisz tworzyć nowego obrazu BufferedImage. Możesz zastosować metodę wymienioną przez for3st bezpośrednio do oryginalnego obrazu BufferedImage ("image") i ustawić żądaną szerokość i wysokość. W związku z tym potrzebne jest tylko jedno oświadczenie (zawarte w dokumentacji Java firmy stadard):

drawImage(BufferedImage image, int x, int y, int width, int height, ImageObserver observer) 
Powiązane problemy