I have animated transparent gif image and need to display it in android. I tried Component GifImageView, everything is ok but background is black not transparent.
Thanks
Stream input = Assets.Open("oie_2103618iUK1c2Pr.gif");
byte[] bytes;
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
bytes = ms.ToArray();
}
_gifImageView = new GifImageView(this);
_gifImageView.SetBytes(bytes);
_gifImageView.Background = new ColorDrawable(Color.Transparent);
LinearLayout giflayout = FindViewById<LinearLayout>(Resource.Id.gif);
giflayout.AddView(_gifImageView);
try to add:
GifImageView.setBackgroung();
or read this: Transparent GIF in Android ImageView
You can use another library, like Android Gif Drawable (GifImageView does not support transparent gifs), or set backround color (not transpatent) in gif, with gif editor.
you cant set transparent background for gif image. Just remove it with online gif editor. There are a lot of them
The current version of GifImageView doesn't have transparency changes that were just made a few days ago. I was able to get it working by having my Activity inherit from GifImageView.IOnFrameAvailableListener and setting my gifImageView.OnFrameAvailableListener to the Activity(as seen here). The last thing was to implement OnFrameAvailable in the Activity itself.
public Bitmap OnFrameAvailable(Bitmap bitmap)
{
if (bitmap != null) {
var newBitmap = bitmap.Copy (Bitmap.Config.Argb8888, true);
newBitmap.HasAlpha = true;
var pixelArray = new int[bitmap.Width * bitmap.Height];
bitmap.GetPixels (pixelArray, 0, bitmap.Width, 0, 0, bitmap.Width, bitmap.Height);
for (int ctr = 0; ctr <pixelArray.Count(); ctr++)
{
pixelArray[ctr] = pixelArray[ctr] == -16777216 ? 0 : pixelArray[ctr];
}
newBitmap.SetPixels (pixelArray, 0, bitmap.Width, 0, 0, bitmap.Width, bitmap.Height);
return newBitmap;
}
return bitmap;
}
This worked for me, hopefully it works for you too. You may need to change -16777216 to -1 if you see white backgrounds. Hopefully GifImageView gets updated soon, as this post-processing is not ideal.
Related
I am using the FingerPaintCanvasView from this xamarin sample.
I am working with 2 layers. The first layer is an ImageView i want to draw on. The second layer is the PaintCanvasView to draw.
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<ImageView
android:id="#+id/markImageImageView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<fingerpaint.FingerPaintCanvasView
android:id="#+id/canvasMarkMeta"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
The canvas has a transparent background and the layout params of both views are set programmatically. This way the marking works fine.
Now the question is, how can I merge this imageview with the marking canvas with as little as possible quality loss to an singel file (bitmap or imageFile in FileSystem).
Let me explain why I mentiond the quality loss:
For example the image in the background has a size of 1920x1080 from the devices camera. The display only has 1280x800 pixel. Since I can't fit the image in the display, I need to display a scaled down version AND the marking happens on this scaled down version.
EDIT:
#Joe LV:
This is your demo without any changes deployed on my devices:
Lenovo Yoga 3, Android 6.0.1
Huawei Honor 8, Android 7.0
I will try an Android 8 Emulator soon.
Pixel 2XL, Android 8.1
So this method does not Work for API <= 24 :-(
(API 25 and 26 not tested)
markImageImageView just holds an image that I load from the device storage (can be any image)
canvasMarkMeta is the FingerPaintCanvas from the linked template which the holds the drawn lines.
Below is the code, I have add comments in it:
public class MainActivity : Activity
{
private Rect mSrcRect, mDestRect;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
//your background picture ---markImageImageView
Bitmap background = BitmapFactory.DecodeResource(Resources, Resource.Drawable.pause);
//your foreground picture ---FingerPaintCanvasView
Bitmap foreground = BitmapFactory.DecodeResource(Resources, Resource.Drawable.play);
Paint p = new Paint();
p.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.SrcOver));
//use background to create a canvas
Bitmap workingBitmap = Bitmap.CreateBitmap(background);
Bitmap mutableBitmap = workingBitmap.Copy(Bitmap.Config.Argb8888, true);
Canvas c = new Canvas(mutableBitmap);
int mBWith = background.Width;
int mBHeight = background.Height;
int mFWith = foreground.Width;
int mFHeight = foreground.Height;
mSrcRect = new Rect(0, 0, mBWith, mBHeight);
mDestRect = new Rect(0, 0, mFWith, mFHeight);
//draw foreground on the backaground, then they will be single bitmap
c.DrawBitmap(foreground, mSrcRect, mDestRect, p);
ImageView imageView = FindViewById<ImageView>(Resource.Id.iv);
imageView.SetImageBitmap(mutableBitmap);
}
}
And I have provide the demo on github.
Update:
Change Bitmap.Config.Argb4444 to Bitmap.Config.Argb8888.
I am want to display Barcode on android. As input I get SVG string. As a SVG library I use AndroidSVG. I used sample code from library website and everything seem to be fine. But when I zoom on image, I get distorted edges (Anti-alias?). I tried to disable all the flags. But the image still has fuzzy edges. What can be wrong with my code?
Picture:
Try to zoom to max, you will see the fuzzy edges.
Code:
private void loadQRCode(String svgString) {
SVG svg = null;
try {
svg = SVG.getFromString(svgString);
} catch (SVGParseException e) {
e.printStackTrace();
}
if (svg.getDocumentWidth() != -1) {
int widthPx = Utils.pxFromDp(400);
int heightDp = Utils.pxFromDp(300);
svg.setDocumentWidth(widthPx);
svg.setDocumentHeight(heightDp);
int width = (int) Math.ceil(svg.getDocumentWidth());
int height = (int) Math.ceil(svg.getDocumentHeight());
Bitmap newBM = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas bmcanvas = new Canvas(newBM);
final DrawFilter filter = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG, 0);
bmcanvas.setDrawFilter(filter);
barcode.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
bmcanvas.drawRGB(255, 255, 255);
svg.renderToCanvas(bmcanvas);
barcode.setImageBitmap(newBM);
}
}
If the edges of the bars do not lie exactly on pixel boundaries, you will get anti-aliasing. On a high resolution screen, this should not normally be visible.
However, in your code, you are rendering the SVG to a bitmap and setting the bitmap to an ImageView. If that ImageView has a size larger than the bitmap - ie. greater than 400 x 300, then the anti-aliased pixels in that bitmap will likely be rendered larger and thus more visible.
One solution is to avoid using a bitmap. Use a Picture/PictureDrawable instead. That way the barcode will be rendered at highest quality no matter what size it is. As vector graphics are supposed to be.
Follow the example on this page:
http://bigbadaboom.github.io/androidsvg/use_with_ImageView.html
So your code should probably look something like the following:
private void loadQRCode(String svgString) {
try {
SVG svg = SVG.getFromString(svgString);
barcode.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
Drawable drawable = new PictureDrawable(svg.renderToPicture());
barcode.setImageDrawable(drawable);
} catch (SVGParseException e) {
e.printStackTrace();
}
}
If for some reason you need to use bitmaps - maybe you are caching them or something - then you should watch for changes in the size of the ImageView and then recreate the bitmap at the new size. So the bitmap is always the same size as the ImageView to which it is assigned.
Hi i guess this is quite simple solution but i cant figure it out myself.
lets say we have 4 points ( start_X, start_Y, end_X, end_Y) and we have to show the user this selection.
For now i thought best solution was to have 3 imageviews:
Original(nothing changed);
Mask(just any semi transparent color)
Portion(cutted out portion of original image)
and to show them as folows: 3>2>1
This solution would be great but i cant finish it. Stuck at croping an image portion and inserting it in 'the place' it belongs according to original image;
Questions are - Is there any other solution for this problem ? if not then - How to crop part of image using those 4 points and then put this image very exact place it belongs ?
Udate 1
Create new bitmap with transparent background (.png maybe) and same size as original image. Then add the cutted portion to it at special position and use it as image 3(described above); Is this solution correct ? if yes how to do it ?
try this:
class BD extends BitmapDrawable {
private Rect mSelection;
public BD(Resources res, Bitmap bitmap) {
super(res, bitmap);
mSelection = new Rect(20, 20, 60, 60);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Log.d(TAG, "draw " + canvas.getMatrix());
canvas.clipRect(mSelection, Op.DIFFERENCE);
canvas.drawColor(0x66000000);
}
}
test code (place it in onCreate):
ImageView iv = new ImageView(this);
Resources res = getResources();
Bitmap b = BitmapFactory.decodeResource(res, R.drawable.layer0);
Drawable d = new BD(res, b);
iv.setImageDrawable(d);
setContentView(iv);
I'm making a game in AS3 with Adobe Flash Pro CC.
I've made a mobile version for Android but if I put GPU in render mode, my blurred effet or my glow effect doesn't work on the device.
If I put CPU or direct the blurred and glow effects are working but animations are not smooth. (with GPU render, everything is extra smooth !)
Do you know how I can have my blurred effect and my glow effect with GPU render mode ?
Thank you very much,
Stephan
Here's what I did (but it still doesn't work on an actual Android device) :
My code was :
private function itemGlow(isGlowing:Boolean):void{
if (isGlowing){
var glow:GlowFilter = new GlowFilter();
glow.color = 0xFFFF00;
glow.alpha = .75;
glow.blurX = 10;
glow.blurY = 10;
glow.quality = BitmapFilterQuality.MEDIUM;
draggedItem.filters = [glow];
} else {
draggedItem.filters = null;
}
And I replace it with this code :
public function itemGlow(isGlowing:Boolean):void{
if (isGlowing){
var glow:Sprite = new Sprite();
glow.graphics.beginFill(0); // black color
glow.graphics.drawCircle(20, 20, 20);
glow.graphics.endFill();
draggedItem.filters = [new GlowFilter(0xFFFF00, 1)];
var bd:BitmapData = new BitmapData(50, 50, true, 0x00000000);
bd.draw(glow);
var glowbit:Bitmap = new Bitmap(bd);
addChild(glowbit);
} else {
draggedItem.filters = null;
}
No errors, glow visible on the simulation device. But when it's not working on real Android device....
Vector effects and blending modes won't work in GPU mode. If you want to get a glowEffect you will have to calculate it in memory but display a bitmap that has the effect.
Here is a minimalist example:
// creating a glowing sprite in memory
var glowingSprite:Sprite = new Sprite();
glowingSprite.graphics.beginFill(0); // black color
glowingSprite.graphics.drawCircle(20, 20, 20);
glowingSprite.graphics.endFill();
glowingSprite.filters = [new GlowFilter(0xFFFFFF, 1)];
var bd:BitmapData = new BitmapData(50, 50, true, 0x00000000); // when entering size, usually get the size from glowingSprite.getBounds(), it will return the size with the filter
bd.draw(glowingSprite);
var b:Bitmap = new Bitmap(bd);
addChild(b);
As you will see you can now work with filters and blend modes!
If you want an animation, just create an array of bitmapData objects and in the bitmap object change the bitmapData property on each frame.
From Adobe:
The following limitations exist when using GPU rendering mode in AIR
2.5 and above:
Filters are not supported.
Source
I need to draw a bitmap on another bitmap, but I only want to draw on top of pixels that have a specific color (transparent in this case) .
I understand that AvoidXfermode could do that, but it is deprecated since API 16.
Is there a different method to this now ?
Thank you
I received the right answer in my private inbox, so I will share it here:
There is no replacement method.
AvoidXfermode was deprecated because it is not supported in hardware. However, it can still be used when drawing on bitmaps.
Another method, of course, is to go pixel by pixel, and replace the ones with a specific color, but that's not what I was looking for.
Here we go, assuming bitmap sizes are the same.
var image1, image2;
var newCanvas = document.createElement('canvas');
var newContext = newCanvas.getContext('2d');
newCanvas.width = image1.width;
newCanvas.height = image1.height;
newContext.drawImage(image1, 0, 0);
var imgData = newContext.getImageData(0,0,newCanvas.width, newCanvas.height);
newContext.drawImage(image2, 0, 0);
var imgData2 = newContext.getImageData(0,0,newCanvas.width, newCanvas.height);
for (var i = 0; i < imgData.data.length; i += 4) {
if( imgData.data[i] < 20 //If Red is less than 20
&& imgData.data[i+1] == 40 //If Green is 40
&& imgData.data[i+2] >= 240 //If Blue is over 240
&& imgData.data[i+3] >= 240) //If Alpha is over 240
{
imgData.data[i] = imgData2.data[i];
imgData.data[i+1] = imgData2.data[i+1];
imgData.data[i+2] = imgData2.data[i+2];
imgData.data[i+3] = imgData2.data[i+3];
}
}
imgData2 = null;
newContext.putImageData(imgData, 0, 0);
That should just copy it over as is if any pixel meets those parameters.
The end result is either imgData, a byte array of data that you can draw using putImageData, or a canvas (which you can essentially use as a new Image)