I want to save a Lottie animation as video (mp4 or any other video format).
Here's a list of what I've tried:
How to save Lottie Animation as Video (.mp4) and GIF (.gif) in Android?
I tried with this Lottie Recorder Test lib. But I'm still getting issue with this lib also
Someone told me to record surfaceview using this lib. but How to draw each frame of lottie onto the canvas?
I really do know know how to draw each frame in surfaceview from Lottie
public class MyLottieAnimationView extends LottieAnimationView {
SurfaceHolder holder;
public void setHolder(SurfaceHolder holder) {
this.holder = holder;
}
public MyLottieAnimationView(Context context) {
super(context);
}
public MyLottieAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLottieAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
Canvas c = holder.lockCanvas();
if (c == null) {
Log.e(TAG, "Cannot draw onto the canvas as it's null");
} else {
Bitmap myBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.RGB_565);
canvas.setBitmap(myBitmap);
c.drawBitmap(myBitmap, 0, 0, new Paint());
// c.
// drawMyStuff(canvas);
holder.unlockCanvasAndPost(canvas);
}
super.onDraw(canvas);
}
}
val lottieComposition = LottieCompositionFactory.fromRawResSync(this, R.raw.android_wave) // your lottie json file
val lottieDrawable = LottieDrawable()
lottieDrawable.composition = lottieComposition.value
val path = getExternalFilesDir(Environment.DIRECTORY_PICTURES) ?: File(cacheDir, Environment.DIRECTORY_PICTURES).apply { mkdirs() }
val videoFile = File(path, "lottie_in_video.mp4")
val recordingOperation = RecordingOperation(Recorder(videoOutput = videoFile), FrameCreator(lottieDrawable))
{
textView.text = getString(R.string.recording_finished)
openCreatedVideo(videoFile)
}
then call on save button
recordingOperation.start()
refrence : https://github.com/rogererill/LottieRecorderTest
Related
I want to render a camera preview inside a circle, like this:
I have it working inside a fragment added to an activity. But I would like to show the view above other apps by adding it to the WindowManager.
So what I have working is showing views above other apps but the SurfaceView does not clip at all. And separately I have the SurfaceView clipping to circle, but in a fragment.
I have read many answers here and articles about this topic. There is very little info about cropping a SurfaceView, and no library that does what I want. Most of the info I found only explains how to crop it to a square or some other rectangle.
How it looks when added to WindowManager
I am trying to dra
How can I clip a SurfaceView that is shown above all views?
SurfaceView subclass
public class CircleSurface extends SurfaceView {
private Path clipPath;
public CircleSurface(Context context) {
super(context);
init();
}
public CircleSurface(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleSurface(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setZOrderMediaOverlay(true);
setWillNotDraw(false);
SurfaceHolder sfhTrackHolder = getHolder();
sfhTrackHolder.setFormat(PixelFormat.TRANSPARENT);
clipPath = new Path();
//TODO: define the circle you actually want
clipPath.addCircle(710, 330, 250, Path.Direction.CW);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(clipPath);
super.dispatchDraw(canvas);
}
}
Service that adds views to the window manager
public class LiveStreamingService extends Service implements SurfaceHolder.Callback {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(startId, getNotification());
}
sharedInstance = this;
// android shouldn't auto restart this service
return START_NOT_STICKY;
}
#Override
public void onCreate() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
// camera view
CircleSurface cameraSurfaceView = new CircleSurface(this);
cameraSurfaceView.getHolder().addCallback(this);
wm.addView(cameraSurfaceView, getLayoutParams(360, 270));
}
private WindowManager.LayoutParams getLayoutParams(int width, int height) {
int overlayType = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O
? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
: WindowManager.LayoutParams.TYPE_PHONE;
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
width,
height,
overlayType,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
);
return layoutParams;
}
// ...
}
UPDATE
Seems like the camera rendering is somehow separate from the dispatchDraw method. I can do whatever in dispatchDraw and the camera keeps showing as a rectangle.
Created a drawing thread for the surface view that listens to the camera preview callback with OnPreviewFrame.
Inside the thread's drawing loop:
c.drawColor(0, PorterDuff.Mode.CLEAR);
c.drawColor(0x1000000); // magical color that removes everything (like transparency)
if (currentFrame == null) return;
c.clipPath(circleSurfaceView.path);
c.drawBitmap(currentFrame, 0, 0, paint);
I have no idea what the magical color is. I came across it by luck. Everything else I tried would just draw black or fuzzy noise.
I have an Android app where i need to take a photo, display it and then be able to put a mark icon it.
I succeeded in taking the picture and displaying it on an ImageView, but now i try to put the mark on it, so i searched and found that a good solution was to subclass ImageView, so that's what i did, but when i draw the canvas on my custom Imageview it's blank...
This is how i do, first my custom ImageView :
public class CustomImageView extends AppCompatImageView {
private Point mTouch;
private Bitmap mMarker;
public CustomImageView(Context context) {
super(context);
init();
}
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mTouch = new Point();
mMarker = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.ic_mark);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
mTouch = new Point(Math.round(event.getX()), Math.round(event.getY()));
}
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas c) {
super.onDraw(c);
Paint paint = new Paint();
c.drawBitmap(mMarker, mTouch.x, mTouch.y, paint);
}
}
And Where i use it :
....
mCustomImageView = (CustomImageView) view.findViewById(R.id.mypic);
....
File imgFile = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES),"mypic.jpg");
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
Bitmap myMutableBitmap = myBitmap.copy(Bitmap.Config.RGB_565,true);
mCanvas = new Canvas(myMutableBitmap);
mCustomImageView.draw(mCanvas);
Then nothing shows... seems that mCustomImageView is empty, and of course onDraw is never fired as i can't draw on it.
But if i use this :
mCustomImageView.setImageBitmap(myMutableBitmap);
Then the image is showing, and touch events are sent. But i think this way i don't draw on the canvas, and onDraw is not fired as well...
Any hint ?
onDraw is not called after touch event.Adding invalidate() to onTouchEvent to force refresh may resolve your problem.
I make gif Files animated then, I put this one in the Application's imageview.
GlideDrawableImageViewTarget imageViewTarget = new GlideDrawableImageViewTarget(character6);
Glide.with(this).load(R.raw.company_normal8).into(imageViewTarget);
here's code and I have no problem with apply this one.
But I have serious issue that The image have afterimage.
I made this gif file with photoshop and It have 2 frame
There's A frame and B frame.
But at android app,
A -> B -> A -> B (this is the normal one)
But My app
A -> A+B -> A -> A+b (like this afterimage)
You can use asGif
Glide.with(context)
.load(imgUrl)
.asGif()
.placeholder(R.drawable.img)
.crossFade()
.into(imageView);
OR
Try this if Glide is not working for you,Its working for me
public class GIFView extends View{
Movie movie;
long moviestart;
public GIFView(Context context) throws IOException {
super(context);
}
public GIFView(Context context, AttributeSet attrs) throws IOException{
super(context, attrs);
}
public GIFView(Context context, AttributeSet attrs, int defStyle) throws IOException {
super(context, attrs, defStyle);
}
public void loadGIFResource(Context context, int id)
{
//turn off hardware acceleration
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
InputStream is=context.getResources().openRawResource(id);
movie = Movie.decodeStream(is);
}
public void loadGIFAsset(Context context, String filename)
{
InputStream is;
try {
is = context.getResources().getAssets().open(filename);
movie = Movie.decodeStream(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (movie == null) {
return;
}
long now=android.os.SystemClock.uptimeMillis();
if (moviestart == 0) moviestart = now;
int relTime;
relTime = (int)((now - moviestart) % movie.duration());
movie.setTime(relTime);
movie.draw(canvas,10,10);
this.invalidate();
}
}
XML
<yourpackagename.GIFView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
android:layout_marginTop="110dp"
android:src="#drawable/yourgifimage"/>
To set the image
imagevw.loadGIFResource(this, R.drawable.yourgifimage);
I am looking to implement a feature that allows me to take predefined borders/images and place them over top a picture that a user has taken.
This app would be very similar to the functionality of Aviary, or Photo Editing Apps.
I cannot seem to figure out how to draw many images (say mustaches, noses, etc..) onto a canvas or view.
Is there a specific method to accomplishing this stacked bitmap/filter editing? I tried creating a custom View, but I can only set 1 setContentView();
My code is relatively simple right now, but I just wanted to know if there was a method of stacking views, or bitmaps individually.
public class CustomView extends View {
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomView(Context context, AttributeSet attrs) {
super(context);
}
#Override
public void onDraw (Canvas canvas) {
//Draw stuff in here
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.basketball);
canvas.drawBitmap(bitmap, 0, 0, null);
}
}
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
CustomView m_View = new CustomView(this);
setContentView(m_View);
}
}
This logic can be implemented many ways. It is based on your requirements and details of the application. Basically you can do something similar to this:
#SuppressLint("WrongCall")
#Override
protected void onDraw(Canvas canvas) {
// use for-int to avoid object (iterator) allocations
int count = mItems.size();
for (int i = 0; i < count; i++) {
mItems.get(i).onDraw(canvas);
}
}
ArrayList<Item> mItems;
static class Item {
Context mContext;
Drawable mDrawable;
Rect mRect;
int mResourceId;
// resource ID to point to drawable resources
public Item(Context context, int resourceId) {
mContext = context;
mResourceId = resourceId;
mRect = new Rect();
}
public void onDraw(Canvas canvas) {
// allocate image only when it actually required
if (mDrawable == null) {
mDrawable = mContext.getResources().getDrawable(mResourceId);
}
// manage mRect to place sticker and etc.
if (mDrawable != null) {
mDrawable.setBounds(mRect);
mDrawable.draw(canvas);
}
}
}
I am trying to create a 2D avatar customizer without using a Game Engine inside my Android app.
I will basically have a PNG image as a base to start with. Then I want to layer other images on top of the base to customize the character.
What would be the best option to create this? I have already created a custom ImageView and overrided the onDraw():
public class AvatarView extends ImageView {
public AvatarView(Context context) {
super(context);
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char), 0, 70, null);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat), 70, 0, null);
}
}
This seems very specific by using coordinates. Would there be a better way to achieve this without having to use coordinates?
EDIT:
Here is what I have so far. The guy is a separate image from the red hat.
If you are planning to add on that ImageView dynamically then there is not way to place those images without assigning pixel axis on it
one problem in your custom class is that dont ever decodeResource within your onDraw method that it will be called multiple times and it will cause a big lag problem, instead create an init method within your AvatarView and decode it, and call that init method in all of your constructor.
sample:
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init()
{
body = getResources(), R.drawable.battle_run_char);
hat = getResources(), R.drawable.red_cartoon_hat);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(BitmapFactory.decodeResource(body , 0, 70, null);
canvas.drawBitmap(BitmapFactory.decodeResource(hat , 70, 0, null);
}
}