======순서======

[0] 과거 문제 상황

[1] 그동안 시도했으나 실패한것

[2] gif파일들 webp로 변환

[2.0] s3에서 gif 리소스 모두 다운로드

[2.1] .bat(for windows) 작성

[2.2] s3(cdn)에 업로드

[2.3] android gif 랜더링 기능담당하는 클래스 일부 변경

[2.4] 개선 및 마무으리

================

 

[0] 과거 문제 상황

1. 서비스하고 있는 app의 기능중에 이런것이 있음

-- 이미지(gif)를 클릭할때마다 다른 이미지(gif)로 교체.

2. 이미지(gif)의 크기(약 3~5MB)가 있는데 app에 다 때려박을수는 없어서리

(apk사이즈가 너무 커지니깐. 게임도 아닌데)

3. amazon s3를 cdn용도로 서비스할 gif들(약 170개)을 업로드 하고

4. app에서 1.과 같은 기능 호출 시 웹으로 다운받아 app Imageview로 랜더링 함.

5. 랜더링 라이브러리로는 Glide 4.7.0 사용중

6. 1~5와 같은 flow로 서비스중인데 gif의 사이즈가 그래도 꽤 큰편이라 네트워크 속도기준 4g로도 이미지 교체 요청 시 꽤 로딩 시간이 길어짐 (약3초정도)

 

[1] 그동안 시도했으나 실패한것

- webview로 랜더링 :

크롬에서 띄우는 gif는 로딩 없이(혹은 짧게) 스트리밍으로 재생되는것에 착안하여 웹서버에 gif띄우고, 안드로이드 app에 웹뷰를 띄워 웹뷰의 gif 스트리밍 기능을 이용해 봄직하여 시도함.

안드로이드 웹뷰의 클릭이벤트를 받아 이미지 교체 시 gif가 로딩없이 바로 스트리밍 되는것은 확인했으나. 컨텐츠를 제외한 바탕화면의 투명처리도 가능했으나

화질이 그렇게 좋지 아니했다. 꽤 많이 차이났었던 기억

 

- 영상 스트리밍하듯이 gif 스트리밍 방법을 파봄 :

위 webview가 gif 스트리밍 기능을 갖고있는 것에 착안하여 imageview든 어떤 레이아웃이든 gif 스트리밍이 가능한 라이브러리가 있을것이라고 판단되었음. 

그러나 안드로이드에서의 gif의 스트리밍 관련 라이브러리 찾기 어렵고 직접 작성 시 시간 너무 오래걸릴것같음

 

- 기존 리소스인 gif들을 mp4 변환하여 영상 스트리밍 처리 :

mp4 또한 gif보다 매우 적은 용량을 가질 수 있음 (프레임이나 화질같은 퀄리티는 별차이없음)

exoplayer를 이용하여 클릭 이벤트(영상 교체), 클릭없을 시 무한반복재생 등으로 구현 가능해 보이고 테스트 성공하였으나 영상 컨텐츠를 제외한 안드로이드 레이아웃상 exoplayerview 전체 뷰가 투명처리되어야 했는데 이부분에서 방법을 못찾음.

 

... 그래서 찾은게 webp였음.

webp는 그대로 webp 키워드로 검색만해도 어떤 것인지 잘 나오므로 설명은 생략함.

 

[2] gif파일들 webp로 변환

약 166개에 달하는 gif들을 webp로 변환했을 시 gif 용량이 약 1/10으로 줄어듬.

제일 큰 용량의 gif가 약 6MB정도이므로 webp 변환시 사이즈인 약 600KB정도면 현재 app의 비즈니스로직을 변경없이 그대로 가져가더라도 이미지 교체 시의 로딩이 현저히 줄어들 것으로 예상됨.

 

webp를 구글에서 만들었기 때문에 연관되는 툴을 제공할것으로 판단함.

마침 구글에서 https://developers.google.com/speed/webp/docs/gif2webp 와 같이 gif파일을 webp로 변환해주는 툴을 제공하여 사용함.

 

[2.0] s3에서 gif리소스 모두 다운로드

s3 콘솔에서 직접 리소스 파일들 모두 다운받을려고 하니 복수개 파일 다운로드를 제공하지 않음 -.-;;

기존 사용하던 ftp client인 filezilla는 s3 ftp 접속할려면 프로버전 구매해라 해서 다른 툴 찾아봄.

s3 접속이 가능한 cyberduck 툴을 사용해봄. (프리웨어, 종료할때마다 도네이션 요청 창 뜸.)

https://cyberduck.io/

 

Cyberduck | Libre server and cloud storage browser for Mac and Windows with support for FTP, SFTP, WebDAV, Amazon S3, OpenStack

Amazon CloudFront Manage custom origin, basic and streaming CloudFront distributions. Toggle deployment, define CNAMEs, distribution access logging and set the default index file.

cyberduck.io

다른 클라이언트 툴로 aws 서비스 계정 써야하는 상황인데 루트사용자 계정 쓰기 좀 찝찝해서

s3 접속용 IAM 계정 하나 만든다음 이걸로 cyberduck이용하여 s3 ftp 접속

[[s3에서 iam 계정 권한 설정 및 생성하면 credential-csv 다운받을 수 있는데 이거 다운받아서 계정정보들 userid, secretKey들 cyberduck 접속 설정할때 집어넣으면 접속됨.]]

cyberduck쓰니까 s3 복수파일다운로드 가능해짐.

본인 사용하기 적절한 디렉토리에 모두 다운받음.

 

[2.1] .bat(for windows) 작성

간단 사용법 테스트 하고 나는 약 170개의 gif파일을 일괄적으로 .webp로 변환하는것이 목적이므로

windows 10 에서 가능하도록 배치파일(.bat) 작성

@ECHO ==ConvertGifInputToWebpOutput==
cd C:\dev-Source\libwebp-1.0.2-windows-x64\libwebp-1.0.2-windows-x64\bin
REM C:\dev-Source\libwebp-1.0.2-windows-x64\libwebp-1.0.2-windows-x64\bin
FOR %%f IN (input/*.gif) DO gif2webp -v -lossy input/%%f -o output/%%f.webp

회색 문장 중 DO 구문 뒤의 명령어가 gif2webp 툴 명령어임.

gif2webp -v(로그출력) -lossy(압축기능사용, 안쓰면 in/output 용량 변화없음) input/*.gif -o output/*.webp 뭐 이런뜻임.

뭐 이런식으로 4줄 쓰고 돌리니까 일괄 변환은 잘 되었음

166개 변환하는데 싱글쓰레드로 약 15분 걸림.

webp변환된 파일네임이 *.gif.webp 이런식으로 붙어서 나와서 파일네임도 일괄 변경할까 했으나 필요없을 작업으로 판단되어(랜더링함에 문제없을것) & gif에서 webp로 변환되었구나 하고 보기 편하라고 & 귀차니즘 으로 계속진행.

 

[2.2] s3에 .webp들 업로드

업로드는 cyberduck을 안쓰고 s3 콘솔에 직접 업로드하였음.

cyberduck으로 업로드 하니까 퍼블릭 액세스 설정을 건너뛰고 업로드 되는데 default로 퍼블릭엑세스를 '허용안함'으로 업로드 하는 것 같음.

왜냐면 cyberduck으로 파일 하나 업로드 해놓고 s3에서 제공하는 url로 외부 접속하니 access denied 뜨면서 파일 컨텐츠 접근 안됨.

 

[2.3] android gif 랜더링 기능 담당하는 클래스 변경

기존 gif 랜더링은 Glide 4.7.0 으로 아래와 같이 ImageView에 랜더링하였다.

Glide.with(context)
	 .asGif()
     .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
     .transition(DrawableTransitionOptions.withCrossFade(600))
     .load(GIF_URI + gifFileName)
     .into(targetImageView);

.load(https://s3.ap-northeast-2.amazonaws.com/app/filename.gif) 뭐 이런식으로 들어가면서 랜더링 하였다

.asGif() 옵션에서는 webp 랜더링이 불가했다 (에러발생)

.asGif()삭제하면 이미지 랜더링은 가능하나 gif와 같이 움직이는 애니메이션이 불가했다. (고정된 첫번째 프레임의 이미지만 랜더링되고 이미지 멈춤)

 

좀 찾아보니 고맙게도 webp 애니메이션을 지원하는 라이브러리 있었음.

https://github.com/zjupure/GlideWebpDecoder

 

zjupure/GlideWebpDecoder

A Glide WebpDecoder Intergration Library for decoding and displaying webp images - zjupure/GlideWebpDecoder

github.com

필요조건으로 다음과 같이 그래들 빌드 필요했음

implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
implementation 'com.zlc.glide:webpdecoder:1.5.4.9.0'

 

위 GlideWebpDecoder 적용하여 아래와 같이 변경.

Transformation<Bitmap> circleCrop = new CircleCrop();
Glide.with(Objects.requireNonNull(mContext))
   	.load(GIF_URI + gifFileName)
    .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
	.optionalTransform(WebpDrawable.class, new WebpDrawableTransformation(circleCrop))
	.transition(DrawableTransitionOptions.withCrossFade(600))
	.into(targetImageView);

 

성공하여 app 비즈니스로직의 큰 변경없이 Glide에 떨궈주는 이미지파일의 변경만으로 webp 이미지 랜더링이 가능하였다

이미지 교체시 로딩 속도도 현저히 줄었다만...

... 다른 문제가 발생

 

[2.4] 개선 및 마무으리

이미지(gif)가 교체될 때 transition crossfade로 구현하였었다 뭔말이냐면

=교체 이벤트 발생 시

=기존이미지 fade out (600ms)

=새로운 이미지 fade in (600ms)

 

[2.3]까지 처럼 구현했을 때 새로 다운받아 오는 이미지(webp)는 위 의도대로 잘 동작하였으나

교체된 이미지가 이미 캐싱처리 되었을 때. (이미 한번 cdn에서 다운받은 이미지일때.)

(..그렇다 조건에 따라 교체이벤트 발생 시 어떤 이미지를 불러올건지 list traversing하며 반복하여 교체된다.)

교체'될' 이미지는 fadeout해서 사라졌으나

캐싱된 이미지는 fade in 애니메이션 듣지 않고 그야말로 뿅! 하면서 튀어나온다. 부자연스럽다.

 

내가 지금 할 삽질은 누군가 과거에 이미 한 삽질이라는 명언이 있으므로

아래와 같이 찾아보니 Glide를 이용해서 코틀린 코드로 누군가 해결해 놓았다.

https://stackoverflow.com/questions/53664645/how-to-apply-animation-on-cached-image-in-glide

 

How to apply animation on cached image in Glide

I want to show the image using Glide animation. I'm downloading this image from the server. The animation is working fine when it downloads from the server but it's not working when the image is ta...

stackoverflow.com

 

현재 플젝에는 코틀린을 적용하지 않았으므로 자바 코드로 포팅하여 아래와 같이 구현 하였다.

class DrawableAlwaysCrossFadeFactory implements TransitionFactory<Drawable> {
		private DrawableCrossFadeTransition resourceTransition = 
        		new DrawableCrossFadeTransition(600,true);
		@Override
		public Transition<Drawable> build(DataSource dataSource, boolean isFirstResource) {
			return resourceTransition;
		}
	}

그리고 이미지 랜더링 하는 Glide 코드는 아래와 같이 변경

Glide.with(Objects.requireNonNull(mContext))
		.load(GIF_URI + gifFileName)
		.optionalTransform(WebpDrawable.class, new WebpDrawableTransformation(circleCrop))
		.transition(DrawableTransitionOptions.with(new DrawableAlwaysCrossFadeFactory()))
		.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
		.into(targetImageView);

 

 

+ Recent posts