October
Игра “Меморина” (Java Swing GUI Game) и проблема с ImageIcon
Posted in: Java GUI, Swing, AWT, SWT, Java technologies, J2SE |
Ну прямо гейм-девелопер какой-то.
Попросили меня написать маленькую игрушечку с использованием графической библиотеки Java Swing. Игра всем знакома и называется “Меморина”.
Думаю, заказчик не будет сильно зол за то, что я выложу игру на всеобщее обозрение…
Еще столкнулся с такой проблемой: при загрузке картинок из jar-файла возникает исключительная ситуация ImageFormatException, хотя при запуске из IDE все проходит без ошибок.
Для тех, кому хочется поскорее увидеть игрушку, - memory.zip (54 Kb)
А вот stack-trace того, что я увидел после запаковки классов и иконок в jar:
Premature end of JPEG file sun.awt.image.ImageFormatException: JPEG datastream contains no image at sun.awt.image.JPEGImageDecoder.readImage(Native Method) at sun.awt.image.JPEGImageDecoder.produceImage(Unknown Source) at sun.awt.image.InputStreamImageSource.doFetch(Unknown Source) at sun.awt.image.ImageFetcher.fetchloop(Unknown Source) at sun.awt.image.ImageFetcher.run(Unknown Source)
В результате небольшого разбирательства обратил внимание на этот код:
InputStream is = Memorina.class
.getResourceAsStream(iconName);
byte[] buffer = new byte[is.available()];
is.read(buffer);
ImageIcon imgIcon = new ImageIcon(buffer);
Экземпляр класса ImageIcon использовался для создания объекта JButton.
Но ImageIcon можно получить и другим способом:
ImageIcon imgIcon = new ImageIcon(img),
где img - объект Image.
Этот объект можно получить через java.awt.Toolkit. В итоге получаем следующий код, который отлично достает картинки из jar’a:
URL url = Memorina.class.getResource(iconName); Image img = Toolkit.getDefaultToolkit().getImage(url);
Проблема решена.
Жду ваших комментариев и замечаний.
5 Comments »
RSS feed for comments on this post.
Думаю проблема в строчке
byte[] buffer = new byte[is.available()];
Вероятно InputStream, возвращаемый класслодером для ресурса из jar-ки не реализует метод available (честно говоря и не должен), и возвращает всегда 0. Т.е. закладываться на этот метод в данном случае нельзя. Нужно сделать ByteArrayOutputStream baos, скопировать в него при помощи буфера фиксированого размера то что нужно из InputStream, и потом использовать byte[] полученый из baos.toByteArray().
Предположение хорошее, но я это тоже проверял. Дело в том, что при запуске программы из IDE все работает, а не работает именно после запаковки классов и картинок в jar.
ХМ. странно. такого быть не должно. А в пути к самой jar-ке случаем нет папки, имеющей в имени восклицательный знак.
Нету, но восклицательный знак - не проблема. Попробуй написать простенькую програмку используя куски кода из статьи и убедишься сам. Я использовал JDK 1.4.2, может в 1.5 уже все и исправили…
А можно полный исходник ? Или тогда заказчик уж точно обидется?