i'm using fresco to display images to my app. Right now i'm trying to apply some filters to my images but the problem is that the filter library only results Bitmap. But the draweeView.setImageBitmap is deprecated.
I also tried with a post processor like this
MeshPostprocessor meshPostprocessor = new MeshPostprocessor();
meshPostprocessor.setFilter(filters.get(0));
draweeView = (SimpleDraweeView) view.findViewById(R.id.filter_image);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(image)
.setPostprocessor(meshPostprocessor)
.setResizeOptions(new ResizeOptions(100, 100))
.build();
PipelineDraweeController controller = (PipelineDraweeController)
Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(draweeView.getController())
.build();
draweeView.setController(controller);
and here is the PostProcessor
public static class MeshPostprocessor extends BaseRepeatedPostProcessor {
private AbstractConfig.ImageFilterInterface filter;
public void setFilter(AbstractConfig.ImageFilterInterface filter) {
this.filter = filter;
update();
}
#Override
public String getName() {
return "meshPostprocessor";
}
#Override
public void process(Bitmap bitmap) {
bitmap = filter.renderImage(bitmap);
}
}
so when I click on a filter i just run this
meshPostprocessor.setFilter(colorFilterConfig.get(position));
I tried with the debugger, the code goes through all the methods (setFilter , process etc..) but the image is not changing at all...
What am i missing?
I think you don't need a BaseRepeatedPostProcessor in your case.
A normal BasePostProcessor should be sufficient here.
However, the issue seems to be your custom filter:
#Override
public void process(Bitmap bitmap) {
bitmap = filter.renderImage(bitmap);
}
I suppose it returns a different Bitmap? This does not work in Java / for Fresco.
If your filter can do the processing in place, you can use process(Bitmap bitmap) and directly modify the given bitmap (e.g. bitmap.setPixel(...)).
If you cannot do it in place, you can override process(Bitmap destBitmap, Bitmap sourceBitmap) instead and modify destBitmap.
If your bitmap changes it's size, you can override CloseableReference<Bitmap> process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory). However, in this case make sure to actually use the provided bitmapFactory to create the new bitmap to be efficient.
For more information, take a look at http://frescolib.org/docs/modifying-image.html for more information or check out the JavaDoc for BasePostprocessor.
ok so the way I solved this is by adding a super call on the process like this
#Override
public void process(Bitmap dest, Bitmap source) {
Bitmap filtered = filter.renderImage(source, intensity);
super.process(dest, filtered);
}
i didn't noticed that you have to call super in order for the changes to have effect.
Somebody recently commented on my code where I declare the following:
private Bitmap splashBackground;
private Bitmap lightDot;
private static Bitmap scaledBackground;
private static Bitmap scaledLightDot;
They advised me against declaring satic Bitmaps.
However, I've tried everything and my code doesn't work unless I declare them as static.
Also, "public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)" seems to appear on the official Android Developer site so I'm a bit confused about what I should and shouldn't be doing.
Any pointers would be appreciated - thank you
Edit: For clarification:
When I remove the static from my declaration, then by the time I get to my onDraw() method, the scaled bitmap is null. (I am creating the scaled bitmap object in an initialise() method and once it's been created, it is valid (ie, not null) - but then seems to become null at onDraw unless I declare it as static.
I am calling my initialise() method from my activity class.
Edit: More code as requested.
My OnCreate method: As you can see, I'm passing my screen height and width over so I can create my scaled bitmaps
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
displaySplashScreen= new SplashScreen(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// set View
setContentView(new SplashScreen(this));
WindowManager w = getWindowManager();
Display d = w.getDefaultDisplay();
int width=d.getWidth();
int height=d.getHeight();
displaySplashScreen.initialise(width, height);
}
My initalise method:
public void initialise(int w, int h)
{
//Get width and height (passed in from Activity)
vwidth=w;
vheight=h;
//Create pre-scaled bitmaps
scaledBackground = Bitmap.createScaledBitmap(splashBackground, vwidth, vheight, true);
scaledLightDot = Bitmap.createScaledBitmap(lightDot, vwidth, vheight, true);
}
I could add also that if I use a standard variable in the same way (say int number;) and set it in initalise (number = 5;), then number is only equal to 5in my initialise method. If I log it from onDraw() it will always repeatedly return '0'!! It's baffling.
Thanks everyone so far, please let me know if more code is required......
In general, utilizing static for Bitmaps is a very bad idea. There are a lot of good reasons for this, mostly having to do with avoiding memory leaks.
Also, "public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)" seems to appear on the official Android Developer site ...
This is not a static Bitmap. This is a method call to a class method. Static does not work the same and the return type (Bitmap) is not static. What this means is that the method is static and does not require an instance to be called. It will return a Bitmap to be placed in an appropriate variable of your choice.
I am calling my initialise() method from my activity class.
This statement is quite unhelpful. From where in the class is it being called? Is it in onCreate(), onStart(), onResume(), some other custom method? Where and when you choose to do certain things can have a huge effect as to how successful they are.
... but then seems to become null at onDraw unless I declare it as static.
This could be for several possible reasons, and since we don't have any of your code there really isn't a qualified answer. Here are some things to look at.
This could be because the Activity is getting recreated.
This could also be because some method that seems unrelated is actually getting called. This would probably be somewhere that you are manually setting it to null.
This might be due to improper use of the createScaledBitmap() method.
The Bitmap might be getting recycled due to low memory (this actually happens more often than one would think)
EDIT: After reviewing your code
This looks like it may be the culprit. Above, you have...
displaySplashScreen= new SplashScreen(this);
Below, you add...
setContentView(new SplashScreen(this));
This means that you are creating two Splashscreens. One reason why you are getting a null pointer when you are not using static may be because further down the line you use...
displaySplashScreen.initialise(width, height);
But since your contentView is set to a new SplashScreen, you are not actually utilizing that View. To resolve this, make sure you are talking to the same view object. I.E.
setContentView(displaySplashScreen);
This will at least make sure you are looking at the same object. It is possible that you may have to reorganize a bit depending upon what other things are happening. For instance,
setContentView(displaySplashScreen);
... may have to appear below ...
displaySplashScreen.initialise(width, height);
This is something that you might have to toy with, but I don't see anything else that gives any other immediate indication. Be aware that resolving nullpointerexceptions will often result in revealing more errors in code, at first. Stay the course and resolve each in order.
This line is wrong:
// set View
setContentView(new SplashScreen(this)); // This line is wrong.
Should be this:
// set View
setContentView(displaySplashScreen); // displaySplashScreen is created earlier.
You are created two instances of SplashScreen. You should keep using the same instance.
I vote for nay,
this one is a static variable
private Bitmap splashBackground;
private Bitmap lightDot;
private static Bitmap scaledBackground;
private static Bitmap scaledLightDot;
and this one is a static method
public static Bitmap createScaledBitmap (Bitmap src,
int dstWidth, int dstHeight, boolean filter)
static variable is usually declared for a constant and the variable belongs to class not object as an example if you have a class
public class car {
private static colorOfCar;
private numberOfDoor;
}
let's say you have a class car and have 2 variable colorOfCar and numberOfDoor when you create an object porsche and ferrari from car class if you change the number of door it's OK the numberOfDoor in your porsche object and ferrari object will be different, but if you change the colorOfCar both porsche object and ferrari object colorOfCar will be changed because the colorOfCar is a static object that belong to the class not the object.
I hope you understand my explanation. If you find my answer helping you please vote and accept my answer and if you have any other question feel free to ask in the comment, thank you :)
Without your code, it seems you are using your view is being created more than once. Maybe in two instances of the view, or maybe the same view being recreated (Activity restarting). In the first time around, initialize() is being called before onDraw(), making your static Drawable initialized and valid. The second time around, onDraw() is running before initialize() (which works when Drawable is static). This is most likely due to you inflating the view and calling initialize() afterwards (this means the view is already in the layout). i.e.
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.mylayout); //the view is added to layout, onDraw() may be called
MyView view = (MyView)findViewById(R.id.myview);
view.initialize(); //initializing the drawable from null
//no guarentee that initialize was called before onDraw()
}
This runs ok when your Drawable is static because when the second view is drawn, it is using the same Drawable which was initialized by the first view. When you remove the static, you need to make sure initialize is always called before onDraw().
Instead of calling initialize() from your activity, why not invoke it from the View's constructor? I often use the following pattern:
public class MyView extends View {
private Bitmap splashBackground;
private Bitmap lightDot;
private Bitmap scaledBackground;
private Bitmap scaledLightDot;
public MyView(Context context) {
super(context);
init();
}
public MyView(AttributeSet attr, Context context) {
super(attr, context);
//parse attr for xml attributes
init();
}
private void init() {
splashBackground = getResources().getDrawable(R.drawable.splash_background);
lightDot = getResources().getDrawable(R.drawable.light_dot);
scaledLightDot = Bitmap.createScaledBitmap(lightDot, getDPI(32), getDPI(32), false);
}
public void onSizeChanged(int width, int height) {
scaledBackground = Bitmap.createScaledBitmap (splashBackground, width, height, false);
}
/**
* Convert pixel value to device independent pixels (DPI)
* #params pixels Value for pixel size for MDPI screens
*/
private int getDPI(int pixels) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, pixels, getResources().getDisplayMetrics());
}
public void onDraw(Canvas canvas) {
//non-static drawables are guaranteed to be not-null
canvas.draw(scaledBackground, 0, 0, null);
canvas.draw(scaledLightDot, 10, 10, null);
}
}
You'll be all set
I've been trying to load a bitmap in a non-activity class but everything I've done so far has failed. I have even tried to send the Context as reference, but this also results in error.
My current situation looks like this:
// Surface class
public class GameScreen extends SurfaceView implements Callback {
TileSet ts;
public GameScreen(Context context, AttributeSet attr) {
// Here I send context as a reference
ts = new TileSet(context, R.drawable.tiles);
}
}
// This is the class I need to get resources
public class TileSet {
public TileSet(Context context, int id) {
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), id);
}
}
Any ideas?
Have you tried just getting the bitmap in the Activity and then passing that to the constructor of your GameScreen?
I'm getting a NullPointerException when running this bit of code
abstract class thing extends Drawable(){
Bitmap sprite;
int spriteResource;
public thing(){
setResources();
sprite=Bitmap.createBitmap(sprite,src.left,src.top,(src.right-src.left),(src.bottom-src.top),m,true);
}
#Override
public void draw(Canvas c){
bit= Bitmap.createBitmap(sprite,0,0,45, 45);// Generates the exception
c.drawBitmap(bit, x, y, null);
}
abstract void setResource();
}
class otherThing extends thing(){
#Override
public void setResource(){
spriteResource=R.drawable.otherThing_sprite;
}
}
Basically i'm trying to load different sprites into different classes by using the method of the parent class. But the spriteResource doesn't get set and I can't understand why?
I set up the log which returned the Resource as 0. Any ideas why this is happening or how to resolve it???
Thanks
When createBitmap in thing() is trying to give the sprite variable a value, sprite is one of its in-parameters, this means that you are trying to use sprite before it is created and you get a null pointer exception.
I use a surfaceview to draw a pie chart in Android. In order to know how big the pie slice should be I need to pass a parameter to the onDraw() method. How can I do this? Inside the onDraw() I make a query to a datahelper-class that fetches the right data.
I tried to call a static function in one Activity from the onDraw, and which function returned an integer. But I want something more dynamic, so I can send the integers I need to from the Activity to the onDraw and just get the result in form of a pie chart.
Any suggestions?
One of solutions can be like this:
public class MySurfaceView extends SurfaceView
{
private MyParameter parameter;
public void setParameter(MyParameter parameter)
{
this.parameter=parameter;
}
#Override
public void onDraw(Canvas canvas)
{
if(this.parameter==null)
return; //nothing to draw...
//draw here...
}
}
//somewhere in code
MySurfaceView sView=(SurfaceView )findViewById(R.id.pie_chart);
//
sView.setParameter(new MyParameter(100,2000, false));
}