2010-11-18 21 views
7

Devo ridimensionare un'immagine con Java JAI. Al tempo, io uso il seguente codice:Ridimensionamento delle immagini con Java JAI

private static RenderedOp scale(RenderedOp image, float scale) { 
    ParameterBlock scaleParams = new ParameterBlock(); 
    scaleParams.addSource(image); 
    scaleParams.add(scale).add(scale).add(0.0f).add(0.0f); 
    scaleParams.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2)); 

    // Quality related hints when scaling the image 
    RenderingHints scalingHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
    scalingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
    scalingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
    scalingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
    scalingHints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
    scalingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); 
    scalingHints.put(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY)); 

    return JAI.create("scale", scaleParams, scalingHints); 
} 

Purtroppo, questo porta a risultati molto male, soprattutto perché spesso devo scalare le immagini con un fattore di scala inferiore a 0,5 ...

Qualsiasi consigli?

+0

Questa linea appare sospettoso scaleParams.add (scala) .add (scala) .add (0.0f) .add (0.0f); – whatnick

+0

Alcuni esempi di risultati per illustrare cosa intendi per cattivo ti aiuteranno anche a identificare il tipo di artefatto che stai riscontrando. – whatnick

+0

Qualsiasi motivo per non usare 'AffineTransformOp'? Vedi anche http://stackoverflow.com/questions/4216635 – trashgod

risposta

15

Immagino che stai tentando di ridimensionare un'immagine più grande fino a una dimensione di anteprima o una differenza ugualmente grande dall'immagine originale a quella in scala?

Se così, questo argomento è stato effettivamente affrontato da Chris Campbell dal Java2D nel 2007 (non mi aspetto che tu lo sapessi, sottolineando solo che è una domanda comune) perché i nuovi approcci di ridimensionamento Java2D (RenderingHints.VALUE_INTERPOLATION_ *) non ha fornito un equivalente all'approccio deprecato Image.getScaledInstance(SCALE_AREA_AVERAGING or SCALE_SMOOTH).

Come si vede, gli approcci SCALE_AREA_AVERAGING o SCALE_SMOOTH nel vecchio approccio Image.getScaledInstance di Java 1.1 erano un'operazione costosa e multi-step che stava facendo molto lavoro in background per generare quell'immagine dall'aspetto piacevole.

Chris ha sottolineato che il modo nuovo e "corretto", utilizzando Java2D, per ottenere lo stesso risultato è un processo incrementale di ridimensionamento dell'immagine a metà e fino a quando viene raggiunta la dimensione desiderata dell'immagine, preferibilmente utilizzando un valore più alto -qualità della scala come RenderHints.VALUE_INTERPOLATION_BICUBIC o BILINEAR.

Il risultato risulta quasi identico all'approccio Image.getScaledInstance originale che la gente desidera.

In realtà sono andato a cercare questa risposta pochi mesi fa mentre stavo scrivendo un servizio di hosting di immagini e sono rimasto sorpreso dalla complessità della semplice domanda "Come faccio a fare una bella miniatura in Java?" divenne.

Alla fine creo una piccola libreria Java (Apache 2, open source) che implementa 3 diversi approcci al ridimensionamento delle immagini in Java usando "best practice" incluso l'approccio incrementale suggerito da Chris.

La libreria è denominata imgscalr. È possibile scaricare e utilizzare il più semplice:

BufferedImage thumbnail = Scalr.resize(srcImage, 150); 

Non ci sono più opzioni per impostare e utilizzare (ad esempio, la qualità o la velocità della scala), ma fuori dalla scatola ci sono impostazioni predefinite intelligenti per tutto per fare un bel cerca immagini scalate per te, così non devi preoccuparti di più se non vuoi. La libreria fa anche uno sforzo per smaltire ed evitare qualsiasi allocazione di oggetti che non è assolutamente necessaria e smaltire immediatamente le istanze di BufferedImage se non è necessario: è destinato a essere codice come parte di un'app server con esecuzione prolungata, quindi questo era critica.

Ho già creato alcune versioni della libreria e, se preferisci semplicemente strappare le "cose ​​buone" e fare qualcosa con te stesso, provaci. È tutto su GitHub e nessuno di questi è top secret, solo un tentativo di rendere la vita delle persone più facile.

Spero che questo aiuti.

+0

Questa libreria suona molto intrigante. Adoro la scrittura/motivazione i miei primi esempi hanno funzionato bene. Non l'abbiamo ancora adottato (in attesa di ulteriori analisi). –

+0

@MichaelEaster Felice di sapere che sta andando bene finora; Non vedo l'ora di ulteriori feedback! –

3

Ho ottenuto buoni risultati con Thumbnailator. Non so cosa dovrebbe fare JAI.KEY_BORDER_EXTENDER, ma suppongo che il resto della funzionalità (antialias, dithering, ecc.) Sia supportato. ho usato per generare le miniature in scala di grigi di abbastanza grandi immagini in bianco e nero

1

se siete fortunati e avete solo il nero & immagini bianche, quindi è possibile utilizzare un'operazione molto veloce e di buona qualità: SubsampleBinaryToGray

Problemi correlati