Loading Images from sd card to grid view causes bitmap exceeds VM budget - android-gridview

In my Application im loading images from sd card almost 40 to 50 images in grid view for this i created adapter in which constructor loads images from sd card to global variable of array list of bitmaps with in get view im returning bitmap from array list the problem is from this activity user will move to other activity where he will delete image after deletion user will come back to grid activity and have to load the adapter again this creates "bitmap exceeds vm budget". so i don't know is this way to load images from sd card is there any better approach for that any libraries available for loading images from sd card with out memory leak
public class PicAdapter extends BaseAdapter {
int defaultItemBackground;
private Context galleryContext;
Bitmap placeholder;
public PicAdapter(Context c) {
// instantiate context
galleryContext = c;
// create bitmap array
bitmaplist=new ArrayList<Bitmap>();
GlobalData.imageBitmaps = new WeakReference<ArrayList<Bitmap>>(bitmaplist);
imageDescription = new ArrayList<String>();
imagetitle = new ArrayList<String>();
picturesCursor.moveToFirst();
int i = 0;
for (i = 0; i < picturesCursor.getCount(); i++) {
String imagepath = picturesCursor.getString(picturesCursor
.getColumnIndex("img"));
File cacheimage=new File(imagepath);
if(!cacheimage.exists())
{
dBopenHelper.deleteHappyMoments(imagepath);
}
else
{
Bitmap bitmap =
ViewUtils.decodeSampledBitmapFromResource(imagepath,
AppConstants.FRAME_WIDTH,
AppConstants.FRAME_HEIGHT);
ViewUtils.recycleBitmapFrame();
GlobalData.imageBitmaps.get().add(bitmap);
imageDescription.add(picturesCursor.getString(picturesCursor
.getColumnIndex("image_description")));
imagetitle.add(picturesCursor.getString(picturesCursor
.getColumnIndex("image_title")));
picturesCursor.moveToNext();
}
}
if (i == picturesCursor.getCount()) {
Bitmap bitmap = (Bitmap) BitmapFactory.decodeResource(getResources(), R.drawable.add_new);
GlobalData.imageBitmaps.get().add(bitmap);
imageDescription.add(
"Click Add to new Pictures..............");
}
// get the styling attributes - use default Andorid system resources
}
// BaseAdapter methods
// return number of data items i.e. bitmap images
public int getCount() {
return bitmaplist.size();
}
// return item at specified position
public Object getItem(int position) {
return position;
}
// return item ID at specified position
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = (ImageView) getLayoutInflater().inflate(
R.layout.item_grid_image, null);
convertView.setLayoutParams(new GridView.LayoutParams(
AppConstants.FRAME_WIDTH, AppConstants.FRAME_HEIGHT));
}
galleryImageView = (ImageView) convertView;
galleryImageView.setImageBitmap(GlobalData.imageBitmaps.get().get(position));
public void addPic(Bitmap newPic) {
// set at currently selected index
GlobalData.imageBitmaps.get().add(currentPic, newPic);
}
// return bitmap at specified position for larger display
public Bitmap getPic(int posn) {
// return bitmap at posn index
return GlobalData.imageBitmaps.get().get(posn);
}
}
sample code helps me alot
thanks in advance

If your images have high dimension- you need to display them one by one using some kind of queue.
Make sure that you decode them correctly.

Related

CharmListView Infinite Scroll

I need basically an event that triggers at each 200 records loaded, so more data can be loaded until the end of data.
I tried to extend CharmListCell and using the method updateItem like this:
#Override
public void updateItem(Model item, boolean empty) {
super.updateItem(item, empty);
currentItem = item;
if (!empty && item != null) {
update();
setGraphic(slidingTile);
} else {
setGraphic(null);
}
System.out.println(getIndex());
}
But the System.out.println(getIndex()); method returns -1;
I would like to call my backend method when the scroll down gets the end of last fetched block and so on, until get the end of data like the "infinite scroll" technique.
Thanks!
The CharmListCell doesn't expose the index of the underlying listView, but even if it did, that wouldn't be of much help to find out if you are scrolling over the end of the current list or not.
I'd suggest a different approach, which is also valid for a regular ListView, with the advantage of having the CharmListView features (mainly headers and the refresh indicator).
This short sample, created with a single view project using the Gluon IDE plugin and Charm 5.0.0, shows how to create a CharmListView control, and fill it with 30 items at a time. I haven't provided a factory cell, nor the headers, and for the sake of simplicity I'm just adding consecutive integers.
With a lookup, and after the view is shown (so the listView is added to the scene) we find the vertical ScrollBar of the listView, and then we add a listener to track its position. When it gets closer to 1, we simulate the load of another batch of items, with a pause transition that represents a heavy task.
Note the use of the refresh indicator. When new data is added, we scroll back to the first of the new items, so we can keep scrolling again.
public class BasicView extends View {
private final ObservableList<Integer> data;
private CharmListView<Integer, Integer> listView;
private final int batchSize = 30;
private PauseTransition pause;
public BasicView() {
data = FXCollections.observableArrayList();
listView = new CharmListView<>(data);
setOnShown(e -> {
ScrollBar scrollBar = null;
for (Node bar : listView.lookupAll(".scroll-bar")) {
if (bar instanceof ScrollBar && ((ScrollBar) bar).getOrientation().equals(Orientation.VERTICAL)) {
scrollBar = (ScrollBar) bar;
break;
}
}
if (scrollBar != null) {
scrollBar.valueProperty().addListener((obs, ov, nv) -> {
if (nv.doubleValue() > 0.95) {
addBatch();
}
});
addBatch();
}
});
setCenter(new VBox(listView));
}
private void addBatch() {
listView.setRefreshIndicatorVisible(true);
if (pause == null) {
pause = new PauseTransition(Duration.seconds(1));
pause.setOnFinished(f -> {
int size = data.size();
List<Integer> list = new ArrayList<>();
for (int i = size; i < size + batchSize; i++) {
list.add(i);
}
data.addAll(list);
listView.scrollTo(list.get(0));
listView.setRefreshIndicatorVisible(false);
});
} else {
pause.stop();
}
pause.playFromStart();
}
}
Note also that you could benefit from the setOnPullToRefresh() method, at any time. For instance, if you add this:
listView.setOnPullToRefresh(e -> addBatch());
whenever you go to the top of the list and drag it down (on a mobile device), it will make another call to load a new batch of items. Obviously, this is the opposite behavior as the "infinite scrolling", but it is possible as well with the CharmListView control.

How to populate a tableview cell with an image from Sqlite database in JavaFX?

I am trying to populate a tableView cell with an image stored on a Sqlite database using JavaFX. I have found some really good information on here and feel like I am getting pretty close. If there is no image I would like it to keep the constraints to make the cells the same size always. The images stored on the database are 300x300, but the rows will be much smaller. So far the code I have is :
public void buildDataAseptic(){
listNum = 1;
data = FXCollections.observableArrayList();
try{
String SQL = "Select * from aseptic_parts_list"; //Order By id
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Part cm = new Part();
cm.id.set(listNum++);
if (rs.getBlob("image") != null ) {
Blob blob = rs.getBlob("image");
byte[] ndata = blob.getBytes(1, (int) blob.length());
image = new Image(new ByteArrayInputStream(ndata));
ImageView imageView = new ImageView();
imageView.setImage(image);
imageView.setFitWidth(70);
imageView.setFitHeight(80);
cm.image.set(image);
}
cm.vendor_part_number.set(rs.getString("vendor_part_number"));
cm.description.set(rs.getString("description"));
cm.quantity.set(rs.getInt("quantity"));
cm.vendor_name.set(rs.getString("vendor_name"));
cm.model_number.set(rs.getString("model_number"));
cm.equipment_id.set(rs.getString("equipment_id"));
data.add(cm);
}
tableView.setItems(data);
}
catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data" + e.getMessage());
}
filterData();
//filterEquipIDData();
}
this is just one particular method that is called from a comboBox. All of the other data is populating fine in the table except the image. In the initialize() method I have the columns set up as:
assert tableView != null;
idCol.setCellValueFactory(
new PropertyValueFactory<Part, Integer>("id"));
imgCol.setCellValueFactory(
new PropertyValueFactory<Object,ImageView>("image"));
pnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_part_number"));
descCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("description"));
quantityCol.setCellValueFactory(
new PropertyValueFactory<Part,Integer>("quantity"));
venCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_name"));
mnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("model_number"));
equipmentIDCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("equipment_id"));
The Part class where the image object is stored is:
public SimpleObjectProperty<Image> image = new SimpleObjectProperty<>();
public Object getImage() {
return image.get();
}
I have been fiddling with this for a few days now and feel pretty close, just no cigar, please help and thanks!
Here is an example for populating TableView cells with images.
The key to the solution is to set the cell value factory and the cell factory appropriately:
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
Where the ImageTableCell class contains an ImageView as the graphic for the cell and updates the ImageView as the underlying image data changes:
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
One thing to note about this implementation is that it assumes that all images are loaded up into the underlying data structure for the table. This means that if you had a lot of rows in the table, you would be consuming massive amounts of data as all images would be loaded into memory. An alternate solution would be for the underlying data structure just to store the address (url) of the image rather than the image data itself, then load up the image in the cell factory (possibly via an LRU cache mechanism). The trade-off between the different approaches, is speed of operation of the GUI and resources consumed as the user interacts (which is what the all in-memory approach here optimizes for), versus a slower GUI but reduced memory footprint (which is what dymanically loading images in the updateItem call would optimize for). In general, I feel it is best to try to keep the speed of the updateItem call very quick, which is why the solution is presented as is.
I won't supply a sample which also integrates SQLLite as I have no knowledge of that technology, so further integration of the solution with a database system is left up to the reader.
Complete Code
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.*;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ImageTable extends Application {
#Override
public void start(Stage stage) {
List<Fish> fish = Arrays.stream(fishData)
.map(data -> new Fish(data[0], new Image(data[1])))
.collect(Collectors.toList());
TableView<Fish> tableView = new TableView<>(FXCollections.observableList(fish));
TableColumn<Fish, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
tableView.getColumns().add(nameColumn);
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
tableView.getColumns().add(imageColumn);
stage.setScene(new Scene(tableView));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
// image license: linkware - backlink to http://www.fasticon.com
private static final String[][] fishData = {
{ "Blue Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Blue-Fish-icon.png" },
{ "Red Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Red-Fish-icon.png" },
{ "Yellow Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Yellow-Fish-icon.png" },
{ "Green FIsh", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Green-Fish-icon.png" }
};
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
public static final class Fish {
private ReadOnlyStringWrapper name;
private ReadOnlyObjectWrapper<Image> image;
public Fish(String name, Image image) {
this.name = new ReadOnlyStringWrapper(name);
this.image = new ReadOnlyObjectWrapper<>(image);
}
public String getName() {
return name.get();
}
public ReadOnlyStringProperty nameProperty() {
return name.getReadOnlyProperty();
}
public Image getImage() {
return image.get();
}
public ReadOnlyObjectProperty<Image> imageProperty() {
return image.getReadOnlyProperty();
}
}
}
Thank you very much jewelsea! I ended up doing what you said, creating another folder to hold the images and using a url to reference the pictures in the folder. The code I used is:
if(rs.getString("image") != null) {
Image img = new Image(rs.getString("image"));
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
} else {
Image img = new Image("/img/NoImageFound.png");
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
}
This code queries the database for the image and if there is none there it uses an image i created for image not found. I did this because it was shortening my database results to only queries that had an image, the else shows all results from the database now. It is good to know that this will make it faster. I am building a parts database for my work with listeners for filtering parts, and that might have been too slow once the database gets really big to have all the parts directly stored on the database. Your help has sent me in the right direction, thanks a million!

Blackberry support multiple resolutions [duplicate]

This question already has answers here:
Supporting multiple screens - Blackberry
(2 answers)
Closed 8 years ago.
I need to design the UI for a blackberry app. This app should support multiple blackberry resolutions.
One way would be to check the screen_width and screen_height every time, and accordingly fetch images from the res folder. Is there any other more efficient, or a better method to do this? I will also need to do the same for font sizes, of text, according to screen size.
Please help me know the standard method to support multiple BB resolutions
You can try, what I have tried in my applications without any issues so far.
Step 1:
Create a separate package like com.your_app_name.uiconfig which will
contain an abstract class say ModelConfig and different classes for
different resolutions like class BB83xxConfig for resolution 320x240
(width x height), class BB95xxConfig for resolution 360 x 480 (width x
height).
Step 2:
ModelConfig class will provide the concrete implementation of the
methods that will be common to all irrespective of the screen
resolutions and the declaration of abstract methods whose concrete
implementation will be provided in the respective classes based on the
screen resolution.
Step 3: Make each and every class, that is implemented for particular resolution extend ModelConfig and provide concrete
implementation of methods as per requirement.
Step 4: Use singleton pattern to get the instance of ModelConfig, so that it is intantiated only once and that instance is used
throughout.
ModelConfig.java (Just a sample)
public abstract class ModelConfig {
private static ModelConfig modelConfig = null;
public static ModelConfig getConfig() {
if (modelConfig == null) {
if (DeviceInfo.getDeviceName().startsWith("83")) {
modelConfig = new BB83xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("85")) {
// 85xx also has 360 x 240 same as 83xx device
modelConfig = new BB83xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("89")) {
modelConfig = new BB89xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("90")) {
modelConfig = new BB90xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("95")) {
modelConfig = new BB95xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("96")) {
modelConfig = new BB96xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("97")) {
modelConfig = new BB97xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("99")) {
modelConfig = new BB99xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("98")) {
// 9800 also has 360 x 480 same as 95xx device
modelConfig = new BB95xxConfig();
}else {
modelConfig = new DefaultConfig();
}
}
return modelConfig;
}
// Font height for the default font used for the application.
public abstract int getApplicationFontHeight();
// Font height for the header label font.
public abstract int getHeaderLabelFontHeight();
// Height for the coloured background of Header.
public abstract int getHeaderBarHeight();
// Height for the individual row in the list.
public abstract int getCustomListRowHeight();
public abstract int getStandardButtonWidth();
public abstract int getStandardLabelWidth();
public abstract int getTitleFontHeight();
// get Background colour for Header.
public int getHeaderBackgroundColor() {
return 0x26406D;
}
// get Bitmap showing Right Arrow.
public Bitmap getBitmapRightArrow() {
return Bitmap.getBitmapResource("right_arrow.png");
}
// get Bitmap rounded black border for editfield.
public Bitmap getBitmapRoundedBorderEdit(){
return Bitmap.getBitmapResource("rounded_border_black.png");
}
// get Bitmap rounded gray border and white background.
public Bitmap getBtmpRoundedBorderBgrnd(){
return Bitmap.getBitmapResource("rounded_border_grey.png");
}
// get Bitmap rounded gray border and white background.
public Bitmap getBtmpTransparentBgrnd(){
return Bitmap.getBitmapResource("img_transparent_background.png");
}
// get Bitmap showing down Arrow.
public Bitmap getBitmapDownArrow(){
return Bitmap.getBitmapResource("down_arrow.png");
}
}
BB95xxConfig.java (just a sample)
/*
* Common resolution 360*480 pixels (width x height)
*/
public class BB95xxConfig extends ModelConfig {
// Font height for the default font used for the application.
// returns Desired height in pixels.
public int getApplicationFontHeight() {
return 18;
}
// Font height for the header label font.
// returns Desired height in pixels.
public int getHeaderLabelFontHeight() {
return 20;
}
// returns Desired height in pixels for the header background.
public int getHeaderBarHeight() {
return Display.getHeight() / 10;
}
public int getCustomListRowHeight() {
return 50;
}
public int getStandardButtonWidth() {
return 108;
}
public int getStandardLabelWidth() {
return 150;
}
public int getTitleFontHeight() {
return 11;
}
}

Transition of images in Windows Forms Picture box

I'm new to Windows Forms, in my project, i need to change the image in the picture box at runtime. I'm able to do that with the help of a timer. The picture just gets changed. Is it possible to do some transitions when image changes, for example fade in, fade out, blur etc.. If possible could some one please let me know how to do it. I searched in net but in vain.Thanks in advance.
Varun
Simply take new code file and paste below code in it
an original answer for the similar question, answer taken from another question
Answer
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
public class BlendPanel : Panel
{
private Image mImg1;
private Image mImg2;
private float mBlend;
public BlendPanel()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
public Image Image1
{
get { return mImg1; }
set { mImg1 = value; Invalidate(); }
}
public Image Image2
{
get { return mImg2; }
set { mImg2 = value; Invalidate(); }
}
public float Blend
{
get { return mBlend; }
set { mBlend = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
if (mImg1 == null || mImg2 == null)
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 0, this.Width, this.Height));
else
{
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
ColorMatrix cm = new ColorMatrix();
ImageAttributes ia = new ImageAttributes();
cm.Matrix33 = mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg2, rc, 0, 0, mImg2.Width, mImg2.Height, GraphicsUnit.Pixel, ia);
cm.Matrix33 = 1F - mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg1, rc, 0, 0, mImg1.Width, mImg1.Height, GraphicsUnit.Pixel, ia);
}
base.OnPaint(e);
}
}
Build your project. You can now drop a BlendPanel from the top of the toolbox onto your form. Here's a sample program that uses it:
private float mBlend;
private int mDir = 1;
public int count = 0;
public Bitmap[] pictures;
public void myPhoto()
{
pictures = new Bitmap[9];
pictures[0] = new Bitmap(#"Library Images\cf3.jpg");
pictures[1] = new Bitmap(#"Library Images\cf4.jpg");
pictures[2] = new Bitmap(#"Library Images\l1.JPG");
pictures[3] = new Bitmap(#"Library Images\l2.JPG");
pictures[4] = new Bitmap(#"Library Images\l3.JPG");
pictures[5] = new Bitmap(#"Library Images\l4.JPG");
pictures[6] = new Bitmap(#"Library Images\l5.JPG");
pictures[7] = new Bitmap(#"Library Images\l6.JPG");
pictures[8] = new Bitmap(#"Library Images\l7.JPG");
timer1.Interval = 50; //time of transition
timer1.Tick += BlendTick;
try
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
catch
{
}
timer1.Enabled = true;
}
private void BlendTick(object sender, EventArgs e)
{
mBlend += mDir * 0.02F;
if (mBlend > 1)
{
mBlend = 0.0F;
if ((count + 1) < pictures.Length)
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
else
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[0];
count = 0;
}
}
blendPanel1.Blend = mBlend;
}
You'll need to modify the new Bitmap(#"yourimagePath"); calls. Build and run. You should see the displayed image smoothly morph from your first image to your second image without any flickering.
I hope it helps for other...
There is no built-in support for such effects, but you can implement them. I'd suggest to write a custom control that renders the image and have a method for fade-swap, fade itself can be reached with alpha-blending drawing with .NET Graphics class.
However, Graphics class isn't very fast, I don't recommend to use this technique for big images. If you need some fancy UI with hw-accelerated effects, take a look at WPF.
Blend effects are easy to get going by using the ColorMatrix class. There's a good example available in my answer in this thread.
A simple way to get a blur is to resize the image, making it smaller, then redraw it back, making it larger. The Graphics.InterpolationMode property affects the type of blur you'll get.
Those are quicky do-it-yourself solutions. Any decent graphics library has these kind of operations built-in. You probably want something free, check out ImageMagick.NET
To put it simply, not without external (3rd-party) libraries.

Java - drawing many images with Graphics.drawImage() and 2-screen buffer strategy distorts and cuts images

I am using a loop to invoke double buffering painting. This, together with overriding my only Panel's repaint method, is designed to pass complete control of repaint to my loop and only render when it necessary (i.e. some change was made in the GUI).
This is my rendering routine:
Log.write("renderer painting");
setNeedsRendering(false);
Graphics g = frame.getBufferStrategy().getDrawGraphics();
g.setFont(font);
g.setColor(Color.BLACK);
g.fillRect(0, 0, window.getWidth(),window.getHeight());
if(frame != null)
window.paint(g);
g.dispose();
frame.getBufferStrategy().show();
As you can see, it is pretty standard. I get the grpahics object from the buffer strategy (initialized to 2), make it all black and pass it to the paint method of my "window" object.
After window is done using the graphics object, I dispose of it and invoke show on the buffer strategy to display the contents of the virtual buffer.
It is important to note that window passes the graphics object to many other children components the populate the window and each one, in turn, uses the same instance of the graphics object to draw something onto the screen: text, shapes, or images.
My problem begins to show when the system is running and a large image is rendered. The image appears to be cut into seveeal pieces and drawn again and again (3-4 times) with different offsets inside of where the image is supposed to be rendered. See my attached images:
This is the original image:
alt text http://img109.imageshack.us/img109/8308/controller.png
This is what I get:
alt text http://img258.imageshack.us/img258/3248/probv.png
Note that in the second picture, I am rendering shapes over the picture - these are always at the correct position.
Any idea why this is happening?
If I save the image to file, as it is in memory, right before the call to g.drawImage(...) it is identical to the original.
Uh, you are using Swing ?
Normally Swing automatically renders the image, you can't switch it off. The repaint()
method is out of bounds because Swing has a very complicated rendering routine due to
method compatibility for AWT widgets and several optimizations, inclusive drawing only
when necessary !
If you want to use the High-Speed Drawing API, you use a component with a BufferStrategy
like JFrame and Window, use
setIgnoreRepaint(false);
to switch off Swing rendering, set up a drawing loop and paint the content itself.
Or you can use JOGL for OpenGL rendering. The method you are using seems completely
at odds with correct Java2D usage.
Here the correct use:
public final class FastDraw extends JFrame {
private static final transient double NANO = 1.0e-9;
private BufferStrategy bs;
private BufferedImage frontImg;
private BufferedImage backImg;
private int PIC_WIDTH,
PIC_HEIGHT;
private Timer timer;
public FastDraw() {
timer = new Timer(true);
JMenu menu = new JMenu("Dummy");
menu.add(new JMenuItem("Display me !"));
menu.add(new JMenuItem("Display me, too !"));
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
setJMenuBar(menuBar);
setIgnoreRepaint(true);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
super.windowClosing(evt);
timer.cancel();
dispose();
System.exit(0);
}
});
try {
backImg = javax.imageio.ImageIO.read(new File("MyView"));
frontImg = javax.imageio.ImageIO.read(new File("MyView"));
}
catch (IOException e) {
System.out.println(e.getMessage());
}
PIC_WIDTH = backImg.getWidth();
PIC_HEIGHT = backImg.getHeight();
setSize(PIC_WIDTH, PIC_HEIGHT);
createBufferStrategy(1); // Double buffering
bs = getBufferStrategy();
timer.schedule(new Drawer(),0,20);
}
public static void main(String[] args) {
new FastDraw();
}
private class Drawer extends TimerTask {
private VolatileImage img;
private int count = 0;
private double time = 0;
public void run() {
long begin = System.nanoTime();
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
GraphicsConfiguration gc = g.getDeviceConfiguration();
if (img == null)
img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
Graphics2D g2 = img.createGraphics();
// Zeichenschleife
do {
int valStatus = img.validate(gc);
if (valStatus == VolatileImage.IMAGE_OK)
g2.drawImage(backImg,0,0,null);
else {
g.drawImage(frontImg, 0, 0, null);
}
// volatile image is ready
g.drawImage(img,0,50,null);
bs.show();
} while (img.contentsLost());
time = NANO*(System.nanoTime()-begin);
count++;
if (count % 100 == 0)
System.out.println(1.0/time);
}
}

Resources