जावा का उपयोग करके छवि की ऊंचाई और चौड़ाई कैसे प्राप्त करें?


106

क्या छवि ऊंचाई और चौड़ाई प्राप्त करने के लिए ImageIO.read का उपयोग करने के अलावा कोई अन्य तरीका है ?

क्योंकि मैं एक मुद्दे का सामना करता हूं जो धागे को बंद करता है।

at com.sun.medialib.codec.jpeg.Decoder.njpeg_decode(Native Method)      
at com.sun.medialib.codec.jpeg.Decoder.decode(Decoder.java:87)      
at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader.decode(CLibJPEGImageReader.java:73)     
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)      
at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.getImage(CLibImageReader.java:320)    
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)     
 at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.read(CLibImageReader.java:384)   
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)      
at javax.imageio.ImageIO.read(ImageIO.java:1400)      
at javax.imageio.ImageIO.read(ImageIO.java:1322)

यह त्रुटि केवल सन ऐप सर्वर पर होती है और इसलिए मुझे संदेह है कि यह एक सन बग है।


क्या त्रुटि? आप केवल एक स्टैक ट्रेस का एक हिस्सा दिखाते हैं (जो कि लगता है jstack)।
जोआचिम सॉयर

क्या आपने इस समस्या का कारण या निर्धारण पाया है? मुझे वही मुद्दा मिल रहा है जहां वह उसी विधि पर थ्रेड लॉक कर रहा है।
टिमोथी चेन

एक बग है जो संबंधित हो सकता है: Bugs.sun.com/bugdatabase/view_bug.do?bug_id=6791502
एडम श्मिडेग

जवाबों:


288

यहाँ कुछ बहुत ही सरल और आसान है।

BufferedImage bimg = ImageIO.read(new File(filename));
int width          = bimg.getWidth();
int height         = bimg.getHeight();

7
यह एक बहुत लंबे रास्ते से सबसे अच्छा जवाब है, और आपके पोस्ट के 17 दिनों बाद किसी और द्वारा पोस्ट किए गए वोट से आपको धोखा दिया गया है। यह शीर्ष उत्तर होना चाहिए नीचे नहीं।
ओवरस्टेनर

34
मैं जो कुछ भी पढ़ रहा हूं, उससे यह पूरी छवि को स्मृति में पढ़ता है। जो सिर्फ चौड़ाई और ऊंचाई पाने के लिए चरम है।
मार्क

7
खराब तरीका: आपको पूरी छवि रेखापुंज को मेमोरी में लोड करने की आवश्यकता होगी जो OOM का बहुत बड़ी छवियों के साथ कारण बनता है
फिर भी

4
प्रश्न विशेष रूप से ImageIO.read का उपयोग करने के अलावा एक रास्ता पूछता है । आपका उत्तर "ImageIO.read का उपयोग करें" है। यह एक अच्छा जवाब क्यों माना जाता है?
ssimm

5
यह ऐसा करने का सबसे खराब तरीका है और मुझे नहीं लगता कि यह इतना भारी क्यों है। यह पूरी छवि को ढेर में लोड करता है जो धीमा है और बहुत सी अनावश्यक मेमोरी का उपभोग करता है।
पैट्रिक फेवरे

72

यह @Kay द्वारा महान पोस्ट का पुनर्लेखन है, जो IOException को फेंकता है और एक प्रारंभिक निकास प्रदान करता है:

/**
 * Gets image dimensions for given file 
 * @param imgFile image file
 * @return dimensions of image
 * @throws IOException if the file is not a known image
 */
public static Dimension getImageDimension(File imgFile) throws IOException {
  int pos = imgFile.getName().lastIndexOf(".");
  if (pos == -1)
    throw new IOException("No extension for file: " + imgFile.getAbsolutePath());
  String suffix = imgFile.getName().substring(pos + 1);
  Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
  while(iter.hasNext()) {
    ImageReader reader = iter.next();
    try {
      ImageInputStream stream = new FileImageInputStream(imgFile);
      reader.setInput(stream);
      int width = reader.getWidth(reader.getMinIndex());
      int height = reader.getHeight(reader.getMinIndex());
      return new Dimension(width, height);
    } catch (IOException e) {
      log.warn("Error reading: " + imgFile.getAbsolutePath(), e);
    } finally {
      reader.dispose();
    }
  }

  throw new IOException("Not a known image file: " + imgFile.getAbsolutePath());
}

मुझे लगता है कि मेरे इनपुट के जवाब के योग्य होने के लिए मेरा प्रतिनिधि पर्याप्त नहीं है।


इसके लिए धन्यवाद! और user194715 द्वारा की गई प्रदर्शन तुलना को देखते हुए, मैं आपके सुझाव को प्रदर्शन और विचार पर विचार करूँगा! धन्यवाद!
आह-शियांग ने

आप भी उपयोग नहीं किया जा सका probeContentType के साथ संयुक्त nio.Files पैकेज से javax.imageio.ImageIO.getImageReadersByMIMEType(mimeType)यदि आप फ़ाइल के प्रकार के कुछ बनना चाहता था?
एजकैशबर्गर

3
साथ ही, .close()लौटने से पहले आपको स्ट्रीम पर कॉल नहीं करना चाहिए ? अन्यथा आप धारा को खुला छोड़ देते हैं
एजकैसेबर्ग

1
@ php_coder_3809625 लॉग इटरेटर में है, इसलिए यह मामला हो सकता है कि एक ImageReader विफल हो जाता है, लेकिन बाद में सफल होता है। यदि वे सभी विफल हो जाते हैं, तो एक IOException उठाया जाता है।
एंड्रयू टेलर

1
आप org.apache.commons.io.FilenameUtils#getExtensionफ़ाइल नाम एक्सटेंशन का पता लगाने के लिए उपयोग करने पर विचार कर सकते हैं ।
पैट्रिक बर्गनर

52

मुझे एक छवि आकार (अधिक सामान्य) पढ़ने का एक और तरीका मिल गया है। आप ImageReaders के सहयोग से ImageIO क्लास का उपयोग कर सकते हैं। यहाँ नमूना कोड है:

private Dimension getImageDim(final String path) {
    Dimension result = null;
    String suffix = this.getFileSuffix(path);
    Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
    if (iter.hasNext()) {
        ImageReader reader = iter.next();
        try {
            ImageInputStream stream = new FileImageInputStream(new File(path));
            reader.setInput(stream);
            int width = reader.getWidth(reader.getMinIndex());
            int height = reader.getHeight(reader.getMinIndex());
            result = new Dimension(width, height);
        } catch (IOException e) {
            log(e.getMessage());
        } finally {
            reader.dispose();
        }
    } else {
        log("No reader found for given format: " + suffix));
    }
    return result;
}

ध्यान दें कि getFileSuffix वह तरीका है जो बिना "पथ के विस्तार देता है।" उदाहरण के लिए: png, jpg आदि उदाहरण कार्यान्वयन है:

private String getFileSuffix(final String path) {
    String result = null;
    if (path != null) {
        result = "";
        if (path.lastIndexOf('.') != -1) {
            result = path.substring(path.lastIndexOf('.'));
            if (result.startsWith(".")) {
                result = result.substring(1);
            }
        }
    }
    return result;
}

यह समाधान बहुत जल्दी है क्योंकि केवल छवि का आकार फ़ाइल से पढ़ा जाता है, न कि पूरी छवि। मैंने इसका परीक्षण किया और ImageIO.read प्रदर्शन की कोई तुलना नहीं है। मुझे आशा है कि किसी को यह उपयोगी लगेगा।


getFileSuffix()nullइस मामले में कोई अच्छा विचार नहीं है, तो अनावश्यक इफ्स और के साथ शुरू होता है।
जिमी टी।

2
नरक हाँ, यह "मूल रूप से बहुत जल्दी है"! मुझे लगता है कि आप उस एक के साथ 'वर्ष के बोध को समझने' के लिए योग्य हैं। चल रही है ImageIO.read()पूरी तरह से पानी से बाहर, दोनों CPU समय और स्मृति के उपयोग के मामले में।
एरोथ

1
सार्वजनिक स्थैतिक स्ट्रिंग getFileSuffix (अंतिम स्ट्रिंग पथ) {if (पथ! = null && path.lastIndexOf (')। = -1) {वापसी path.substring (path.lastIndexOf ('। '))। substring (1) ; } वापसी शून्य; }
नीलांचल

47

मैंने सूचीबद्ध विभिन्न तरीकों में से कुछ का उपयोग करके प्रदर्शन का परीक्षण करने की कोशिश की। कठोर परीक्षण करना कठिन है क्योंकि कई कारक परिणाम को प्रभावित करते हैं। मैंने दो फोल्डर तैयार किए, एक 330 jpg फाइलों के साथ और दूसरा 330 पीएनजी फाइलों के साथ। दोनों मामलों में औसत फ़ाइल का आकार 4Mb था। फिर मैंने प्रत्येक फ़ाइल के लिए गेटडिमेंशन को कॉल किया। GetDimension विधि के प्रत्येक कार्यान्वयन और प्रत्येक छवि प्रकार का अलग-अलग (अलग-अलग रन) परीक्षण किया गया था। यहाँ निष्पादन समय है जो मुझे मिला (jpg के लिए पहला नंबर, png के लिए दूसरा नंबर):

1(Apurv) - 101454ms, 84611ms
2(joinJpegs) - 471ms, N/A
3(Andrew Taylor) - 707ms, 68ms
4(Karussell, ImageIcon) - 106655ms, 100898ms
5(user350756) - 2649ms, 68ms

यह स्पष्ट है कि कुछ विधियाँ आयाम प्राप्त करने के लिए पूरी फ़ाइल को लोड करती हैं, जबकि अन्य केवल छवि से कुछ हेडर जानकारी पढ़कर प्राप्त करते हैं। मुझे लगता है कि अनुप्रयोग प्रदर्शन महत्वपूर्ण होने पर ये संख्याएँ उपयोगी हो सकती हैं।

इस सूत्र में योगदान के लिए आप सभी को धन्यवाद - बहुत मददगार।


3
अब यह एक जवाब है। बहुत बढ़िया!
ssimm

1
जब आप चित्र अपलोड कर रहे थे, तब क्या आपने ढेर स्थान उपयोग का विश्लेषण किया था? इसके अलावा, क्या आपको किसी भी तरीके पर इन परीक्षणों को चलाने के दौरान कोई OOM त्रुटियां मिलीं?
साभारथ

धन्यवाद आपके उत्तर ने मुझे बहुत मदद की। मेरे पास (50k HD pic)
सुन्नी

17

आप jpeg बाइनरी डेटा को एक फ़ाइल के रूप में लोड कर सकते हैं और jpeg हेडर को स्वयं पार्स कर सकते हैं। जिसे आप देख रहे हैं वह 0xFFC0 या फ़्रेम हेडर का प्रारंभ है:

Start of frame marker (FFC0)

* the first two bytes, the length, after the marker indicate the number of bytes, including the two length bytes, that this header contains
* P -- one byte: sample precision in bits (usually 8, for baseline JPEG)
* Y -- two bytes
* X -- two bytes
* Nf -- one byte: the number of components in the image
      o 3 for color baseline JPEG images
      o 1 for grayscale baseline JPEG images

* Nf times:
      o Component ID -- one byte
      o H and V sampling factors -- one byte: H is first four bits and V is second four bits
      o Quantization table number-- one byte

The H and V sampling factors dictate the final size of the component they are associated with. For instance, the color space defaults to YCbCr and the H and V sampling factors for each component, Y, Cb, and Cr, default to 2, 1, and 1, respectively (2 for both H and V of the Y component, etc.) in the Jpeg-6a library by the Independent Jpeg Group. While this does mean that the Y component will be twice the size of the other two components--giving it a higher resolution, the lower resolution components are quartered in size during compression in order to achieve this difference. Thus, the Cb and Cr components must be quadrupled in size during decompression.

हेडर के बारे में अधिक जानकारी के लिए विकिपीडिया की jpeg प्रविष्टि देखें या मुझे यहाँ उपरोक्त जानकारी मिली ।

मैंने नीचे दिए गए कोड के समान एक विधि का उपयोग किया, जो मुझे इस पोस्ट से सूर्य मंचों पर मिला :

import java.awt.Dimension;
import java.io.*;

public class JPEGDim {

public static Dimension getJPEGDimension(File f) throws IOException {
    FileInputStream fis = new FileInputStream(f);

    // check for SOI marker
    if (fis.read() != 255 || fis.read() != 216)
        throw new RuntimeException("SOI (Start Of Image) marker 0xff 0xd8 missing");

    Dimension d = null;

    while (fis.read() == 255) {
        int marker = fis.read();
        int len = fis.read() << 8 | fis.read();

        if (marker == 192) {
            fis.skip(1);

            int height = fis.read() << 8 | fis.read();
            int width = fis.read() << 8 | fis.read();

            d = new Dimension(width, height);
            break;
        }

        fis.skip(len - 2);
    }

    fis.close();

    return d;
}

public static void main(String[] args) throws IOException {
    System.out.println(getJPEGDimension(new File(args[0])));
}

}


अच्छा। लेकिन मुझे लगता है कि इसके बजाय ==192196, 200 और 204 को छोड़कर 192-207 नंबर की जाँच करनी चाहिए।
vortexwolf

या आप com.drewnoakes.metadata-extractorइन हेडर को आसानी से निकालने के लिए लाइब्रेरी का उपयोग कर सकते हैं
विक्टर पेटिट

9

सरल तरीका:

BufferedImage readImage = null;

try {
    readImage = ImageIO.read(new File(your path);
    int h = readImage.getHeight();
    int w = readImage.getWidth();
} catch (Exception e) {
    readImage = null;
}

3
यह केवल चौड़ाई और ऊंचाई जानने के लिए स्मृति में पूरी छवि को पढ़ने की जरूरत है। हां, यह सरल है, लेकिन कई छवियों या विशाल लोगों के लिए बुरा प्रदर्शन करेगा ...
क्लिंट ईस्टवुड

4

ImageIO.read के साथ समस्या यह है कि यह वास्तव में धीमा है। आपको बस इतना करना है कि आकार पाने के लिए इमेज हेडर पढ़ना है। ImageIO.getImageReaderसही उम्मीदवार है।

यहाँ ग्रूवी उदाहरण है, लेकिन यही बात जावा पर लागू होती है

def stream = ImageIO.createImageInputStream(newByteArrayInputStream(inputStream))
def formatReader = ImageIO.getImageWritersByFormatName(format).next() 
def reader = ImageIO.getImageReader(formatReader)
reader.setInput(stream, true)

println "width:reader.getWidth(0) -> height: reader.getHeight(0)"

प्रदर्शन SimpleImageInfo जावा लाइब्रेरी का उपयोग करने के समान था।

https://github.com/cbeust/personal/blob/master/src/main/java/com/beust/SimpleImageInfo.java


क्या है getReaderByFormat?
कोरे तुगे

3

आप टूलकिट का उपयोग कर सकते हैं, इमेजियो की कोई आवश्यकता नहीं है

Image image = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath());
int width = image.getWidth(null);
int height = image.getHeight(null);

अगर आप इमेज लोडिंग को हैंडल नहीं करना चाहते हैं

ImageIcon imageIcon = new ImageIcon(file.getAbsolutePath());
int height = imageIcon.getIconHeight();
int width = imageIcon.getIconWidth();

1
ImageIO के लिए कोई जरूरत नहीं है, लेकिन टूलकिट के लिए की जरूरत है। अंतर क्या है?
डायटनर

ImageIO एक बाहरी निर्भरता है। टूलकिट नहीं
Karussell

ImageIO जावा का हिस्सा है, क्योंकि 1.4 डॉक्स.कोरल.com
dieter

हाँ, शायद यह काम करेगा, क्षमा करें यदि यह भ्रमित था। : जब मैं इसे करने की कोशिश मैं कुछ भागों के लिए जय बात (? शायद अन्य स्वरूपों को पढ़ने के लिए) की जरूरत stackoverflow.com/questions/1209583/...
Karussell

3

आप जावा का उपयोग करके बफ़र्डइमेज ऑब्जेक्ट के साथ छवि की चौड़ाई और ऊंचाई प्राप्त कर सकते हैं।

public void setWidthAndHeightImage(FileUploadEvent event){
    byte[] imageTest = event.getFile().getContents();
                baiStream = new ByteArrayInputStream(imageTest );
                BufferedImage bi = ImageIO.read(baiStream);
                //get width and height of image
                int imageWidth = bi.getWidth();
                int imageHeight = bi.getHeight();
    }

यह पूरी छवि को मेमोरी में लोड करेगा, बहुत बेकार और बहुत धीमा।
अर्गोडेन

1

ImageIO.read के साथ एक बफ़र्ड छवि प्राप्त करने के लिए एक बहुत ही भारी विधि है, क्योंकि यह मेमोरी में छवि की पूरी असम्पीडित प्रतिलिपि बना रहा है। Png के लिए आप pngj और कोड का उपयोग कर सकते हैं:

if (png)
    PngReader pngr = new PngReader(file);
    width = pngr.imgInfo.cols;
    height = pngr.imgInfo.rows;
    pngr.close();
}

0

ImageIOपिछले वर्षों में बहुत संघर्ष करने के बाद , मुझे लगता है कि एंड्रयू टेलर का समाधान अब तक का सबसे अच्छा समझौता है (तेज: उपयोग नहीं ImageIO#read, और बहुमुखी)। धन्यवाद दोस्त!!

लेकिन मैं एक छोटे से स्थानीय फ़ाइल (फ़ाइल / स्ट्रिंग) का उपयोग करने के लिए मजबूर किया जाना है निराश, विशेष रूप से ऐसे मामलों में जहां आप छवि आकार, से कहते हैं, एक बहुखण्डीय / फार्म डेटा अनुरोध जहां आमतौर पर पुनः प्राप्त आ जाँच करना चाहते हैं में था InputPart/ InputStreamकी। इसलिए मैंने जल्दी से एक वैरिएंट बनाया जो स्वीकार करता है File, InputStreamऔर RandomAccessFile, ImageIO#createImageInputStreamऐसा करने की क्षमता के आधार पर ।

बेशक, इस तरह की एक विधि Object input, केवल निजी रह सकती है और आप इसे कॉल करते हुए आवश्यकतानुसार कई बहुरूपिए तरीकों का निर्माण करेंगे। आप यह भी स्वीकार कर सकते हैं Pathके साथ Path#toFile()और URLसाथ URL#openStream()इस विधि को पारित करने से पहले:

  private static Dimension getImageDimensions(Object input) throws IOException {

    try (ImageInputStream stream = ImageIO.createImageInputStream(input)) { // accepts File, InputStream, RandomAccessFile
      if(stream != null) {
        IIORegistry iioRegistry = IIORegistry.getDefaultInstance();
        Iterator<ImageReaderSpi> iter = iioRegistry.getServiceProviders(ImageReaderSpi.class, true);
        while (iter.hasNext()) {
          ImageReaderSpi readerSpi = iter.next();
          if (readerSpi.canDecodeInput(stream)) {
            ImageReader reader = readerSpi.createReaderInstance();
            try {
              reader.setInput(stream);
              int width = reader.getWidth(reader.getMinIndex());
              int height = reader.getHeight(reader.getMinIndex());
              return new Dimension(width, height);
            } finally {
              reader.dispose();
            }
          }
        }
        throw new IllegalArgumentException("Can't find decoder for this image");
      } else {
        throw new IllegalArgumentException("Can't open stream for this image");
      }
    }
  }

-1

इसलिए दुर्भाग्य से, ऊपर से सभी जवाबों की कोशिश करने के बाद, मैं कोशिश करने के अथक समय के बाद उन्हें काम करने के लिए नहीं मिला। इसलिए मैंने खुद असली हैक करने का फैसला किया और मैं यह काम करने के लिए चला गया। मुझे विश्वास है कि यह आपके लिए भी पूरी तरह से काम करेगा।

मैं इस सरल तरीके का उपयोग ऐप द्वारा उत्पन्न छवि की चौड़ाई प्राप्त करने के लिए कर रहा हूं और फिर भी सत्यापन के लिए बाद में अपलोड किया जाना है:

Pls। ध्यान दें: आपको एक्सेस स्टोरेज के लिए अनुमतियों को सक्षम करना होगा।

/ मैंने इसे स्थिर कर दिया और अपनी ग्लोबल क्लास में डाल दिया ताकि मैं इसे केवल एक स्रोत से संदर्भित या एक्सेस कर सकूं और यदि कोई संशोधन होता है, तो यह सभी को सिर्फ एक ही स्थान पर करना होगा। बस जावा में एक DRY अवधारणा को बनाए रखना। (वैसे भी) :) /

public static int getImageWidthOrHeight(String imgFilePath) {

            Log.d("img path : "+imgFilePath);

            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(imgFilePath, o);

            int width_tmp = o.outWidth, height_tmp = o.outHeight;

            Log.d("Image width : ", Integer.toString(width_tmp) );

            //you can decide to rather return height_tmp to get the height.

            return width_tmp;

}


हैलो @gpasch ऐसा कैसे? या तुमने कोशिश की ? यह मेरे लिए पूरी तरह से काम कर रहा है। अन्य किसी भी उदाहरण ने मेरे लिए काम नहीं किया। कुछ ने मुझे कक्षाओं के अजीब आयात करने के लिए और दूसरों के लिए आवश्यक बना दिया जो मुद्दों का कारण बने। मैं वास्तव में आपकी चुनौती के बारे में और जानना चाहता हूं। खड़े होना । । ।
AppEmmanuel

-2

EMF इमेज रीडर के बिना ईएमएफ फ़ाइल का आकार पाने के लिए आप कोड का उपयोग कर सकते हैं:

Dimension getImageDimForEmf(final String path) throws IOException {

    ImageInputStream inputStream = new FileImageInputStream(new File(path));

    inputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);

    // Skip magic number and file size
    inputStream.skipBytes(6*4);

    int left   = inputStream.readInt();
    int top    = inputStream.readInt();
    int right  = inputStream.readInt();
    int bottom = inputStream.readInt();

    // Skip other headers
    inputStream.skipBytes(30);

    int deviceSizeInPixelX = inputStream.readInt();
    int deviceSizeInPixelY = inputStream.readInt();

    int deviceSizeInMlmX = inputStream.readInt();
    int deviceSizeInMlmY = inputStream.readInt();

    int widthInPixel = (int) Math.round(0.5 + ((right - left + 1.0) * deviceSizeInPixelX / deviceSizeInMlmX) / 100.0);
    int heightInPixel = (int) Math.round(0.5 + ((bottom-top + 1.0) * deviceSizeInPixelY / deviceSizeInMlmY) / 100.0);

    inputStream.close();

    return new Dimension(widthInPixel, heightInPixel);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.