JPanel में छवि कैसे जोड़ें?


341

मेरे पास एक जेपीएनएल है जिसमें मैं जेपीईजी और पीएनजी छवियों को जोड़ना चाहता हूं जो मैं मक्खी पर उत्पन्न करता हूं।

सभी उदाहरण मैंने अब तक स्विंग ट्यूटोरियल में देखे हैं , विशेष रूप से स्विंग के उदाहरणImageIcon एस का उपयोग करते हैं ।

मैं इन छवियों को बाइट सरणियों के रूप में उत्पन्न कर रहा हूं, और वे आम तौर पर उदाहरणों में उपयोग किए जाने वाले सामान्य आइकन की तुलना में बड़े होते हैं, 640x480 पर।

  1. क्या किसी छवि को जेपीनेल में प्रदर्शित करने के लिए ImageIcon वर्ग का उपयोग करने में कोई (प्रदर्शन या अन्य) समस्या है?
  2. क्या है हमेशा की तरह यह करने का तरीका है?
  3. ImageIcon वर्ग का उपयोग किए बिना JPanel में छवि कैसे जोड़ें?

संपादित करें : ट्यूटोरियल और एपीआई की अधिक सावधान परीक्षा से पता चलता है कि आप एक इमेज को सीधे जेपीनेल में नहीं जोड़ सकते हैं। इसके बजाय, वे छवि को जेलेबेल के आइकन के रूप में सेट करके समान प्रभाव प्राप्त करते हैं। यह सिर्फ सही नहीं लगता ...


1
आप बाइट सरणियों को कैसे बना रहे हैं, इस पर निर्भर करते हुए, MemoryImageSourceउन्हें जेपीईजी या पीएनजी प्रारूप में परिवर्तित करने की तुलना में उपयोग करने के लिए अधिक कुशल हो सकता है और फिर ImageIOअधिकांश उत्तरों के साथ पढ़ सकते हैं। आप उपयोग करके अपनी छवि डेटा के साथ Imageएक MemoryImageSourceनिर्माण से प्राप्त कर सकते हैं createImage, और एक उत्तर में सुझाए अनुसार प्रदर्शित कर सकते हैं।
एल्डन

मेरे उत्तर की जांच करें stackoverflow.com/questions/43861991/…
tommybee

जवाबों:


252

यहां बताया गया है कि मैं इसे कैसे करता हूं (एक छवि को लोड करने के बारे में थोड़ी अधिक जानकारी के साथ):

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel{

    private BufferedImage image;

    public ImagePanel() {
       try {                
          image = ImageIO.read(new File("image name and path"));
       } catch (IOException ex) {
            // handle exception...
       }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this); // see javadoc for more info on the parameters            
    }

}

17
-1 paintComponent की अवैध कार्यान्वयन के लिए (@Dogmatixed संभवत: इसलिए आप उन redrawing मुद्दों कर रहे) - यह चाहिए इसके पूरा क्षेत्र को कवर करने जा रहा है अगर यह अपारदर्शी (जो डिफ़ॉल्ट है) की रिपोर्ट की गारंटी, सबसे आसान super.paintComponent फोन करके हासिल की
क्लेओपेट्रा

5
@kleopatra, धन्यवाद, मुझे इस बात का अहसास नहीं था कि ... जैवाडॉक के अनुसार: "आगे, यदि आप सुपर के कार्यान्वयन को लागू नहीं करते हैं, तो आपको अपारदर्शी संपत्ति का सम्मान करना चाहिए, यदि यह घटक अपारदर्शी है, तो आपको पूरी तरह से भरना होगा गैर-अपारदर्शी रंग में पृष्ठभूमि। यदि आप अपारदर्शी संपत्ति का सम्मान नहीं करते हैं, तो आप संभवतः दृश्य कलाकृतियों को देखेंगे। " मैं अब उत्तर को अपडेट करूंगा।
ब्रेंडन कैशमैन

8
कृपया Principle of Encapsulationसुपर क्लास की ओवरराइडिंग विधियों का हमेशा सम्मान करें , paintComponent(...)विधि का एक्सेस protectedpublic
स्पेसिफिकेशन

1
यह अच्छा नहीं है, यह छवि को पैनल को आकार देने के बारे में कुछ नहीं करता है। इससे निपटने के लिए बाद में और कोड जोड़ना होगा। JLabel जवाब का उपयोग करने के लिए बहुत सरल है।
केइली जूल

2
@ जोनाथन: मुझे वास्तव में खेद है, कुछ स्रोत के बारे में Principle of Encapsulation। बस प्रोग्रामिंग करते समय याद रखें, बाकी कोड से क्या छिपाया जाना चाहिए, कोड में सब कुछ दिखाई देने के बजाय, उस तरह से बनाए रखा जाना चाहिए। ऐसा लगता है कि यह एक ऐसी चीज़ है जो अनुभव के साथ आती है, जैसा कि प्रत्येक दिन सीखता है। कोई भी पुस्तक एक मूल विचार दे सकती है कि क्या होता है इनकैप्सुलेशन, लेकिन यह है कि हम अपने कोड को कैसे लागू करते हैं जो यह तय करता है कि हम अवधारणा का कितना पालन कर रहे हैं।
nIcE cOw

520

यदि आप JPanels का उपयोग कर रहे हैं, तो संभवतः स्विंग के साथ काम कर रहे हैं। इसे इस्तेमाल करे:

BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);

छवि अब एक स्विंग घटक है। यह किसी भी अन्य घटक की तरह लेआउट की स्थिति के अधीन हो जाता है।


16
कैसे जेलेबेल के आकार के अनुसार छवि को स्केल करें?
कोडिंग_डॉट

1
अच्छा कोड! मैं स्विंग के साथ बहुत अनुभवी नहीं हूँ, लेकिन मुझे यह काम नहीं मिल रहा है। क्या किसी ने इसे jdk 1.6.0_16 में आज़माया है?
एटोरस

3
@ATorras मुझे पता है कि आपने कुछ समय पहले यह पूछा था, लेकिन अगर किसी अन्य newbies के मेरे मुद्दे थे, picLabel.setBounds () के लिए याद रखें;
काइल

क्या मुझे हर बार नया JLabel ऑब्जेक्ट बनाना पड़ता है जब कोई फ़ोटो पुनः लोड किया जाता है?
0x6B6F77616C74

2
@coding_idiot नया JLabel (नया ImageIcon (backgroundImage.getScaledInstance (चौड़ाई, ऊंचाई, Image.SCALE_FAST)));
डेविस

37

फ्रेड हसलाम का तरीका ठीक काम करता है। मुझे फ़ाइलपथ से परेशानी थी, क्योंकि मैं अपने जार के भीतर एक छवि का संदर्भ लेना चाहता हूं। ऐसा करने के लिए, मैंने उपयोग किया:

BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));

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


1
मैंने BufferedImage previewImage = ImageIO.read(new URL(imageURL));सर्वर से अपनी छवियों को प्राप्त करने के लिए पहली पंक्ति को प्रतिस्थापित किया ।
22

जार से छवियों को संदर्भित करने के लिए, इस stackoverflow.com/a/44844922/3211801
नंद

33

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



11
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));

8

आप JPanel को उपवर्गित कर सकते हैं - यहाँ मेरा ImagePanel से एक उद्धरण है, जो किसी भी 5 स्थानों, शीर्ष / बाएँ, शीर्ष / दाएँ, मध्य / मध्य, नीचे / बाएँ या नीचे / दाएँ में से किसी एक में एक छवि डालता है:

protected void paintComponent(Graphics gc) {
    super.paintComponent(gc);

    Dimension                           cs=getSize();                           // component size

    gc=gc.create();
    gc.clipRect(insets.left,insets.top,(cs.width-insets.left-insets.right),(cs.height-insets.top-insets.bottom));
    if(mmImage!=null) { gc.drawImage(mmImage,(((cs.width-mmSize.width)/2)       +mmHrzShift),(((cs.height-mmSize.height)/2)        +mmVrtShift),null); }
    if(tlImage!=null) { gc.drawImage(tlImage,(insets.left                       +tlHrzShift),(insets.top                           +tlVrtShift),null); }
    if(trImage!=null) { gc.drawImage(trImage,(cs.width-insets.right-trSize.width+trHrzShift),(insets.top                           +trVrtShift),null); }
    if(blImage!=null) { gc.drawImage(blImage,(insets.left                       +blHrzShift),(cs.height-insets.bottom-blSize.height+blVrtShift),null); }
    if(brImage!=null) { gc.drawImage(brImage,(cs.width-insets.right-brSize.width+brHrzShift),(cs.height-insets.bottom-brSize.height+brVrtShift),null); }
    }

8
  1. कोई भी समस्या नहीं होनी चाहिए (बहुत बड़ी छवियों के साथ हो सकने वाली किसी भी सामान्य समस्या के अलावा)।
  2. यदि आप एक पैनल में कई छवियों को जोड़ने के बारे में बात कर रहे हैं, तो मैं ImageIconएस का उपयोग करूंगा । एक छवि के लिए, मैं एक कस्टम उपवर्ग बनाने के बारे में सोचूंगा JPanelऔर paintComponentछवि खींचने के लिए इसकी विधि को ओवरराइड करूंगा ।
  3. (देखें 2)

6

JPanelउपवर्ग के लिए लगभग हमेशा गलत वर्ग है। आप उपवर्ग क्यों नहीं करेंगे JComponent?

इसमें थोड़ी समस्या ImageIconहै कि निर्माणकर्ता छवि को पढ़ रहा है। एप्लिकेशन जार से लोड करते समय वास्तव में कोई समस्या नहीं है, लेकिन हो सकता है कि आप संभावित रूप से नेटवर्क कनेक्शन पर पढ़ रहे हों। JDK डेमो में भी AWT- युग के उपयोग के बहुत सारे उदाहरण हैं MediaTracker, ImageObserverऔर मित्र भी।


6

मैं एक निजी परियोजना में बहुत कुछ समान कर रहा हूं, जिस पर मैं काम कर रहा हूं। इस प्रकार अब तक मैंने 1024x1024 तक की छवियों को बिना किसी समस्या के (मेमोरी को छोड़कर) जनरेट किया है और उन्हें बहुत जल्दी और बिना किसी प्रदर्शन समस्या के प्रदर्शित कर सकता है।

जेपीनेल उपवर्ग की पेंट विधि को ओवरराइड करना ओवरकिल है और आपको आवश्यकता से अधिक काम करने की आवश्यकता है।

जिस तरह से मैं यह कर रहा हूँ:

Class MapIcon implements Icon {...}

या

Class MapIcon extends ImageIcon {...}

छवि उत्पन्न करने के लिए आपके द्वारा उपयोग किया जाने वाला कोड इस वर्ग में होगा। मैं एक BufferedImage का उपयोग तब खींचने के लिए करता हूं जब पेंटआईकॉन () कहा जाता है, g.drawImvge (बफ़रमैडम) का उपयोग करें; यह आपकी छवियों को उत्पन्न करते समय किए गए फ्लैशिंग की मात्रा को कम करता है, और आप इसे थ्रेड कर सकते हैं।

अगला मैं जेलेबेल का विस्तार करता हूं:

Class MapLabel extends Scrollable, MouseMotionListener {...}

ऐसा इसलिए है क्योंकि मैं अपनी छवि को एक स्क्रॉल फलक पर रखना चाहता हूं, यानी छवि का प्रदर्शन भाग और आवश्यकतानुसार उपयोगकर्ता को चारों ओर स्क्रॉल करना है।

इसलिए तब मैं MapLabel को होल्ड करने के लिए JScrollPane का उपयोग करता हूं, जिसमें केवल MapIcon होता है।

MapIcon map = new MapIcon (); 
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();

scrollPane.getViewport ().add (mapLabel);

लेकिन आपके परिदृश्य के लिए (बस हर बार पूरी छवि दिखाएं)। आपको MapLabel को शीर्ष JPanel में जोड़ने की आवश्यकता है, और उन सभी को छवि के पूर्ण आकार (GetPreferredSize ()) को ओवरराइड करके आकार देना सुनिश्चित करें।


5

अपनी परियोजना निर्देशिका में एक स्रोत फ़ोल्डर बनाएँ, इस मामले में मैंने इसे छवियाँ कहा है।

JFrame snakeFrame = new JFrame();
snakeFrame.setBounds(100, 200, 800, 800);
snakeFrame.setVisible(true);
snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
snakeFrame.pack();

5

आप स्वयं के ComponentS और SwingX लाइब्रेरी और ImageIOक्लास का उपयोग करने से बच सकते हैं :

File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));

4

यह उत्तर @ shawalli के उत्तर का पूरक है ...

मैं अपने जार के भीतर भी एक छवि का संदर्भ देना चाहता था, लेकिन बफ़रडैमेज होने के बजाय, मैंने यह सरल किया:

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));

1

मैं कई जवाब देख सकता हूं, ओपी के तीन सवालों को संबोधित नहीं कर रहा हूं।

1) प्रदर्शन पर एक शब्द: बाइट सरणियों की संभावना कम होती है जब तक कि आप एक सटीक पिक्सेल बाइट ऑर्डर का उपयोग नहीं कर सकते हैं जो आपके प्रदर्शन एडेप्टर वर्तमान रिज़ॉल्यूशन और रंग की गहराई से मेल खाता है।

सबसे अच्छा ड्राइंग प्रदर्शन प्राप्त करने के लिए, बस अपनी छवि को बफ़रेडइमेज में परिवर्तित करें जो आपके वर्तमान ग्राफिक्स कॉन्फ़िगरेशन के अनुरूप प्रकार के साथ उत्पन्न होती है। CreateCompatibleImage को https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html पर देखें

इन छवियों को किसी भी प्रोग्रामिंग प्रयास के बिना कुछ समय ड्राइंग के बाद डिस्प्ले कार्ड मेमोरी पर स्वचालित रूप से कैश किया जाएगा (यह जावा 6 के बाद से स्विंग में मानक है), और इसलिए वास्तविक ड्राइंग समय की नगण्य राशि लेगा - यदि आपने छवि नहीं बदली है ।

छवि को बदलना मुख्य मेमोरी और GPU मेमोरी के बीच एक अतिरिक्त मेमोरी ट्रांसफर के साथ आएगा - जो धीमा है। इस छवि को बफ़र किए गए "बफ़रिंग" से बचें इसलिए, हर तरह से गेटपिक्सल और सेटपिक्सल करने से बचें।

उदाहरण के लिए, यदि आप एक गेम विकसित कर रहे हैं, तो सभी गेम एक्टर्स को बफ़रेडइमेज में और फिर जेपीनेल को ड्रॉ करने के बजाय, सभी एक्टर्स को छोटे बफ़रमैजेस के रूप में लोड करना और उन्हें अपने जेपीनेल कोड में एक के बाद एक ड्रॉ करना बहुत तेज़ है। उनकी उचित स्थिति - इस तरह कैशिंग के लिए छवियों के प्रारंभिक हस्तांतरण को छोड़कर मुख्य मेमोरी और GPU मेमोरी के बीच कोई अतिरिक्त डेटा स्थानांतरण नहीं है।

ImageIcon हुड के तहत एक बफ़रडैमेज का उपयोग करेगा - लेकिन मूल रूप से उचित ग्राफिक्स मोड के साथ एक बफ़रेडआईमेज आवंटित करना कुंजी है, और यह अधिकार करने का कोई प्रयास नहीं है।

2) ऐसा करने का सामान्य तरीका JPanel की एक ओवरराइड पेंटकंपोनेंट विधि में एक बफ़रडैमेज खींचना है। हालाँकि, Java एक अतिरिक्त मात्रा में अतिरिक्त अच्छाइयों का समर्थन करता है, जैसे कि GPU मेमोरी में कैश की जाने वाली VolatileImages को नियंत्रित करने वाली बफर चेन, इनमें से किसी का भी उपयोग करने की आवश्यकता नहीं है क्योंकि Java 6, जो GPU त्वरण के इन सभी विवरणों को उजागर किए बिना यथोचित अच्छा काम करता है।

ध्यान दें कि GPU त्वरण कुछ संचालन के लिए काम नहीं कर सकता है, जैसे पारभासी छवियों को खींचना।

3) न जोड़ें। जैसा कि ऊपर बताया गया है, बस उसे पेंट करें:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, this); 
}

"जोड़ना" समझ में आता है अगर छवि लेआउट का हिस्सा है। यदि आपको JPanel को भरने वाली पृष्ठभूमि या अग्रभूमि छवि के रूप में इसकी आवश्यकता है, तो बस PaintComponent में ड्रा करें। यदि आप जेनेरिक स्विंग घटक को पीना पसंद करते हैं जो आपकी छवि दिखा सकता है, तो यह एक ही कहानी है (आप एक JComponent का उपयोग कर सकते हैं और इसकी PaintComponent विधि को ओवरराइड कर सकते हैं) - और फिर इसे GUI घटकों के अपने लेआउट में जोड़ें ।

4) सरणी को बफर्डिमेज में कैसे बदलें

अपने बाइट सरणियों को पीएनजी में परिवर्तित करना, फिर इसे लोड करना काफी संसाधन गहन है। एक बेहतर तरीका यह है कि आप अपने मौजूदा बाइट को बफ़रमैजेज में बदल दें।

उसके लिए: लूप और कॉपी पिक्सल के लिए उपयोग न करें । यह बहुत धीमी गति से होता है। बजाय:

  • BufferedImage की पसंदीदा बाइट संरचना सीखें (आजकल यह RGB या RGBA मानने के लिए सुरक्षित है, जो कि आपके पिक्सेल से 4 बाइट्स है)
  • स्कैनलाइन सीखें और उपयोग में स्कैन करें (जैसे कि आपके पास 142 पिक्सेल चौड़ी छवि हो सकती है - लेकिन वास्तविक जीवन में जो 256 पिक्सेल चौड़ी बाइट सरणी के रूप में संग्रहीत की जाएगी क्योंकि यह तेजी से संसाधित करने के लिए है और जीपीयू हार्डवेयर द्वारा अप्रयुक्त पिक्स को मुखौटा कर सकता है। )
  • एक बार जब आपके पास इन सिद्धांतों के अनुसार एक सरणी निर्माण होता है, तो बफ़रेडइमेज की सेटआरजीबी एरे विधि आपके एरे को बफ़रेडइमेज में कॉपी कर सकती है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.