我有一个html应用程序,我正在处理大量的大图像。我们正在讨论可能有5,000张照片,每张照片大约3-5MB。
到目前为止,我正在测试大约1000张图片,而且事情已经变得很慢了。
我正在使用拖放和FileReader加载图像,然后将FileReader结果设置为图像源:
$ sdiff -t prime.S prime_int.S
prime.o: file format elf64-x86-64 | prime_int.o: file format elf64-x86-64
Disassembly of section .text: Disassembly of section .text:
0000000000000000 <isPrime>: 0000000000000000 <isPrime>:
#else #else
typedef unsigned long long NUM_TYPE ; typedef unsigned long long NUM_TYPE ;
#endif #endif
int isPrime(NUM_TYPE number) int isPrime(NUM_TYPE number)
{ {
0: 55 push %rbp 0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp 1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 50 sub $0x50,%rsp 4: 48 83 ec 50 sub $0x50,%rsp
8: 48 89 7d f0 mov %rdi,-0x10(%rbp) | 8: 89 7d f8 mov %edi,-0x8(%rbp)
if (number < 2) return 0; if (number < 2) return 0;
c: 48 83 7d f0 02 cmpq $0x2,-0x10(%rbp) | b: 83 7d f8 02 cmpl $0x2,-0x8(%rbp)
11: 0f 83 0c 00 00 00 jae 23 <isPrime+0x23> | f: 0f 8d 0c 00 00 00 jge 21 <isPrime+0x21>
17: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) | 15: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
1e: e9 c1 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 1c: e9 88 01 00 00 jmpq 1a9 <isPrime+0x1a9>
if (number == 2) return 1; if (number == 2) return 1;
23: 48 83 7d f0 02 cmpq $0x2,-0x10(%rbp) | 21: 83 7d f8 02 cmpl $0x2,-0x8(%rbp)
28: 0f 85 0c 00 00 00 jne 3a <isPrime+0x3a> | 25: 0f 85 0c 00 00 00 jne 37 <isPrime+0x37>
2e: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp) | 2b: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
35: e9 aa 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 32: e9 72 01 00 00 jmpq 1a9 <isPrime+0x1a9>
if (number == 3) return 1; if (number == 3) return 1;
3a: 48 83 7d f0 03 cmpq $0x3,-0x10(%rbp) | 37: 83 7d f8 03 cmpl $0x3,-0x8(%rbp)
3f: 0f 85 0c 00 00 00 jne 51 <isPrime+0x51> | 3b: 0f 85 0c 00 00 00 jne 4d <isPrime+0x4d>
45: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp) | 41: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
4c: e9 93 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 48: e9 5c 01 00 00 jmpq 1a9 <isPrime+0x1a9>
if (number == 5) return 1; if (number == 5) return 1;
51: 48 83 7d f0 05 cmpq $0x5,-0x10(%rbp) | 4d: 83 7d f8 05 cmpl $0x5,-0x8(%rbp)
56: 0f 85 0c 00 00 00 jne 68 <isPrime+0x68> | 51: 0f 85 0c 00 00 00 jne 63 <isPrime+0x63>
5c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp) | 57: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
63: e9 7c 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 5e: e9 46 01 00 00 jmpq 1a9 <isPrime+0x1a9>
> 63: b8 02 00 00 00 mov $0x2,%eax
if (!(number % 2)) return 0; if (!(number % 2)) return 0;
68: 48 8b 45 f0 mov -0x10(%rbp),%rax | 68: 8b 4d f8 mov -0x8(%rbp),%ecx
6c: 48 83 e0 01 and $0x1,%rax | 6b: 89 45 c0 mov %eax,-0x40(%rbp)
70: 48 83 f8 00 cmp $0x0,%rax | 6e: 89 c8 mov %ecx,%eax
74: 0f 85 0c 00 00 00 jne 86 <isPrime+0x86> | 70: 99 cltd
7a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) | 71: 8b 4d c0 mov -0x40(%rbp),%ecx
81: e9 5e 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 74: f7 f9 idiv %ecx
86: b8 03 00 00 00 mov $0x3,%eax | 76: 83 fa 00 cmp $0x0,%edx
8b: 89 c1 mov %eax,%ecx | 79: 0f 85 0c 00 00 00 jne 8b <isPrime+0x8b>
> 7f: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
> 86: e9 1e 01 00 00 jmpq 1a9 <isPrime+0x1a9>
> 8b: b8 03 00 00 00 mov $0x3,%eax
if (!(number % 3)) return 0; if (!(number % 3)) return 0;
8d: 48 8b 45 f0 mov -0x10(%rbp),%rax | 90: 8b 4d f8 mov -0x8(%rbp),%ecx
91: 31 d2 xor %edx,%edx | 93: 89 45 bc mov %eax,-0x44(%rbp)
93: 48 f7 f1 div %rcx | 96: 89 c8 mov %ecx,%eax
96: 48 83 fa 00 cmp $0x0,%rdx | 98: 99 cltd
9a: 0f 85 0c 00 00 00 jne ac <isPrime+0xac> | 99: 8b 4d bc mov -0x44(%rbp),%ecx
a0: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) | 9c: f7 f9 idiv %ecx
a7: e9 38 01 00 00 jmpq 1e4 <isPrime+0x1e4> | 9e: 83 fa 00 cmp $0x0,%edx
ac: b8 05 00 00 00 mov $0x5,%eax | a1: 0f 85 0c 00 00 00 jne b3 <isPrime+0xb3>
b1: 89 c1 mov %eax,%ecx | a7: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
> ae: e9 f6 00 00 00 jmpq 1a9 <isPrime+0x1a9>
> b3: b8 05 00 00 00 mov $0x5,%eax
if (!(number % 5)) return 0; if (!(number % 5)) return 0;
b3: 48 8b 45 f0 mov -0x10(%rbp),%rax | b8: 8b 4d f8 mov -0x8(%rbp),%ecx
b7: 31 d2 xor %edx,%edx | bb: 89 45 b8 mov %eax,-0x48(%rbp)
b9: 48 f7 f1 div %rcx | be: 89 c8 mov %ecx,%eax
bc: 48 83 fa 00 cmp $0x0,%rdx | c0: 99 cltd
c0: 0f 85 0c 00 00 00 jne d2 <isPrime+0xd2> | c1: 8b 4d b8 mov -0x48(%rbp),%ecx
c6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) | c4: f7 f9 idiv %ecx
cd: e9 12 01 00 00 jmpq 1e4 <isPrime+0x1e4> | c6: 83 fa 00 cmp $0x0,%edx
> c9: 0f 85 0c 00 00 00 jne db <isPrime+0xdb>
> cf: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
> d6: e9 ce 00 00 00 jmpq 1a9 <isPrime+0x1a9>
if (number < 7*7) return 1; if (number < 7*7) return 1;
d2: 48 83 7d f0 31 cmpq $0x31,-0x10(%rbp) | db: 83 7d f8 31 cmpl $0x31,-0x8(%rbp)
d7: 0f 83 0c 00 00 00 jae e9 <isPrime+0xe9> | df: 0f 8d 0c 00 00 00 jge f1 <isPrime+0xf1>
dd: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp) | e5: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
e4: e9 fb 00 00 00 jmpq 1e4 <isPrime+0x1e4> | ec: e9 b8 00 00 00 jmpq 1a9 <isPrime+0x1a9>
int step[] = {7,11,13,17,19,23,29,31}; int step[] = {7,11,13,17,19,23,29,31};
e9: 0f 28 05 00 00 00 00 movaps 0x0(%rip),%xmm0 # | f1: 48 8b 04 25 00 00 00 mov 0x0,%rax
f0: 0f 29 45 e0 movaps %xmm0,-0x20(%rbp) | f8: 00
f4: 0f 28 05 00 00 00 00 movaps 0x0(%rip),%xmm0 # | f9: 48 89 45 d0 mov %rax,-0x30(%rbp)
fb: 0f 29 45 d0 movaps %xmm0,-0x30(%rbp) | fd: 48 8b 04 25 00 00 00 mov 0x0,%rax
> 104: 00
> 105: 48 89 45 d8 mov %rax,-0x28(%rbp)
> 109: 48 8b 04 25 00 00 00 mov 0x0,%rax
> 110: 00
> 111: 48 89 45 e0 mov %rax,-0x20(%rbp)
> 115: 48 8b 04 25 00 00 00 mov 0x0,%rax
> 11c: 00
> 11d: 48 89 45 e8 mov %rax,-0x18(%rbp)
int sentry = (NUM_TYPE)sqrt((double)number); int sentry = (NUM_TYPE)sqrt((double)number);
ff: 0f 28 05 00 00 00 00 movaps 0x0(%rip),%xmm0 # | 121: f2 0f 2a 45 f8 cvtsi2sdl -0x8(%rbp),%xmm0
106: f3 0f 7e 4d f0 movq -0x10(%rbp),%xmm1 | 126: e8 00 00 00 00 callq 12b <isPrime+0x12b>
10b: 66 0f 62 c8 punpckldq %xmm0,%xmm1 | 12b: f2 0f 2c c8 cvttsd2si %xmm0,%ecx
10f: 66 0f 28 05 00 00 00 movapd 0x0(%rip),%xmm0 # | 12f: 89 4d cc mov %ecx,-0x34(%rbp)
116: 00 <
117: 66 0f 5c c8 subpd %xmm0,%xmm1 <
11b: 66 0f 70 c1 4e pshufd $0x4e,%xmm1,%xmm0 <
120: 66 0f 58 c1 addpd %xmm1,%xmm0 <
124: e8 00 00 00 00 callq 129 <isPrime+0x129> <
129: f2 0f 10 0d 00 00 00 movsd 0x0(%rip),%xmm1 # <
130: 00 <
131: 0f 28 d0 movaps %xmm0,%xmm2 <
134: f2 0f 5c d1 subsd %xmm1,%xmm2 <
138: f2 48 0f 2c c2 cvttsd2si %xmm2,%rax <
13d: 48 b9 00 00 00 00 00 movabs $0x8000000000000000,%rcx <
144: 00 00 80 <
147: 48 31 c8 xor %rcx,%rax <
14a: f2 48 0f 2c c8 cvttsd2si %xmm0,%rcx <
14f: 66 0f 2e c1 ucomisd %xmm1,%xmm0 <
153: 48 0f 42 c1 cmovb %rcx,%rax <
157: 89 c2 mov %eax,%edx <
159: 89 55 cc mov %edx,-0x34(%rbp) <
for(int r = 0; r < sentry; r += 30) for(int r = 0; r < sentry; r += 30)
15c: c7 45 c8 00 00 00 00 movl $0x0,-0x38(%rbp) | 132: c7 45 c8 00 00 00 00 movl $0x0,-0x38(%rbp)
163: 8b 45 c8 mov -0x38(%rbp),%eax | 139: 8b 45 c8 mov -0x38(%rbp),%eax
166: 3b 45 cc cmp -0x34(%rbp),%eax | 13c: 3b 45 cc cmp -0x34(%rbp),%eax
169: 0f 8d 6e 00 00 00 jge 1dd <isPrime+0x1dd> | 13f: 0f 8d 5d 00 00 00 jge 1a2 <isPrime+0x1a2>
for(int i = 0; i < 8; ++i) for(int i = 0; i < 8; ++i)
16f: c7 45 c4 00 00 00 00 movl $0x0,-0x3c(%rbp) | 145: c7 45 c4 00 00 00 00 movl $0x0,-0x3c(%rbp)
176: 83 7d c4 08 cmpl $0x8,-0x3c(%rbp) | 14c: 83 7d c4 08 cmpl $0x8,-0x3c(%rbp)
17a: 0f 8d 4a 00 00 00 jge 1ca <isPrime+0x1ca> | 150: 0f 8d 39 00 00 00 jge 18f <isPrime+0x18f>
if (!(number % (r+step[i]))) if (!(number % (r+step[i])))
180: 48 8b 45 f0 mov -0x10(%rbp),%rax | 156: 8b 45 f8 mov -0x8(%rbp),%eax
184: 8b 4d c8 mov -0x38(%rbp),%ecx | 159: 8b 4d c8 mov -0x38(%rbp),%ecx
187: 48 63 55 c4 movslq -0x3c(%rbp),%rdx | 15c: 48 63 55 c4 movslq -0x3c(%rbp),%rdx
18b: 03 4c 95 d0 add -0x30(%rbp,%rdx,4),%ecx | 160: 03 4c 95 d0 add -0x30(%rbp,%rdx,4),%ecx
18f: 48 63 d1 movslq %ecx,%rdx | 164: 99 cltd
192: 31 c9 xor %ecx,%ecx | 165: f7 f9 idiv %ecx
194: 48 89 55 b8 mov %rdx,-0x48(%rbp) | 167: 83 fa 00 cmp $0x0,%edx
198: 89 ca mov %ecx,%edx | 16a: 0f 85 0c 00 00 00 jne 17c <isPrime+0x17c>
19a: 48 8b 75 b8 mov -0x48(%rbp),%rsi <
19e: 48 f7 f6 div %rsi <
1a1: 48 83 fa 00 cmp $0x0,%rdx <
1a5: 0f 85 0c 00 00 00 jne 1b7 <isPrime+0x1b7> <
return 0; return 0;
1ab: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) | 170: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
1b2: e9 2d 00 00 00 jmpq 1e4 <isPrime+0x1e4> | 177: e9 2d 00 00 00 jmpq 1a9 <isPrime+0x1a9>
if (number < 7*7) return 1; if (number < 7*7) return 1;
int step[] = {7,11,13,17,19,23,29,31}; int step[] = {7,11,13,17,19,23,29,31};
int sentry = (NUM_TYPE)sqrt((double)number); int sentry = (NUM_TYPE)sqrt((double)number);
for(int r = 0; r < sentry; r += 30) for(int r = 0; r < sentry; r += 30)
for(int i = 0; i < 8; ++i) for(int i = 0; i < 8; ++i)
if (!(number % (r+step[i]))) if (!(number % (r+step[i])))
1b7: e9 00 00 00 00 jmpq 1bc <isPrime+0x1bc> | 17c: e9 00 00 00 00 jmpq 181 <isPrime+0x181>
if (!(number % 5)) return 0; if (!(number % 5)) return 0;
if (number < 7*7) return 1; if (number < 7*7) return 1;
int step[] = {7,11,13,17,19,23,29,31}; int step[] = {7,11,13,17,19,23,29,31};
int sentry = (NUM_TYPE)sqrt((double)number); int sentry = (NUM_TYPE)sqrt((double)number);
for(int r = 0; r < sentry; r += 30) for(int r = 0; r < sentry; r += 30)
for(int i = 0; i < 8; ++i) for(int i = 0; i < 8; ++i)
1bc: 8b 45 c4 mov -0x3c(%rbp),%eax | 181: 8b 45 c4 mov -0x3c(%rbp),%eax
1bf: 83 c0 01 add $0x1,%eax | 184: 83 c0 01 add $0x1,%eax
1c2: 89 45 c4 mov %eax,-0x3c(%rbp) | 187: 89 45 c4 mov %eax,-0x3c(%rbp)
1c5: e9 ac ff ff ff jmpq 176 <isPrime+0x176> | 18a: e9 bd ff ff ff jmpq 14c <isPrime+0x14c>
if (!(number % (r+step[i]))) if (!(number % (r+step[i])))
return 0; return 0;
1ca: e9 00 00 00 00 jmpq 1cf <isPrime+0x1cf> | 18f: e9 00 00 00 00 jmpq 194 <isPrime+0x194>
if (!(number % 3)) return 0; if (!(number % 3)) return 0;
if (!(number % 5)) return 0; if (!(number % 5)) return 0;
if (number < 7*7) return 1; if (number < 7*7) return 1;
int step[] = {7,11,13,17,19,23,29,31}; int step[] = {7,11,13,17,19,23,29,31};
int sentry = (NUM_TYPE)sqrt((double)number); int sentry = (NUM_TYPE)sqrt((double)number);
for(int r = 0; r < sentry; r += 30) for(int r = 0; r < sentry; r += 30)
1cf: 8b 45 c8 mov -0x38(%rbp),%eax | 194: 8b 45 c8 mov -0x38(%rbp),%eax
1d2: 83 c0 1e add $0x1e,%eax | 197: 83 c0 1e add $0x1e,%eax
1d5: 89 45 c8 mov %eax,-0x38(%rbp) | 19a: 89 45 c8 mov %eax,-0x38(%rbp)
1d8: e9 86 ff ff ff jmpq 163 <isPrime+0x163> | 19d: e9 97 ff ff ff jmpq 139 <isPrime+0x139>
for(int i = 0; i < 8; ++i) for(int i = 0; i < 8; ++i)
if (!(number % (r+step[i]))) if (!(number % (r+step[i])))
return 0; return 0;
return 1; return 1;
1dd: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp) | 1a2: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
} }
1e4: 8b 45 fc mov -0x4(%rbp),%eax | 1a9: 8b 45 fc mov -0x4(%rbp),%eax
1e7: 48 83 c4 50 add $0x50,%rsp | 1ac: 48 83 c4 50 add $0x50,%rsp
1eb: 5d pop %rbp | 1b0: 5d pop %rbp
1ec: c3 retq | 1b1: c3 retq
HTML:
private loadImageFromDisk(image: IImage): Rx.Observable<IImage> {
return Rx.Observable.defer( () => {
console.log( `loading ${image.file.name} from disc` );
console.time( `file ${image.file.name} loaded from file system` );
const reader = new FileReader();
setTimeout( () => reader.readAsDataURL(image.file), 0 ) ;
const subject = new Rx.Subject();
reader.onload = event => {
subject.onNext( reader.result );
subject.onCompleted();
}
return subject
.safeApply(
this.$rootScope,
result => {
console.timeEnd( `file ${image.file.name} loaded from file system` );
image.content = reader.result;
}
)
.flatMap( result => Rx.Observable.return( image ) );
} );
}
我知道ng-repeat可能是一个性能问题,我会对此进行排序,但目前即使显示一个图像也需要几秒钟。如果我从光盘加载图像但实际上没有显示它,则每张图像只需要大约50-100毫秒即可从光盘加载。如果我显示它,事情变得更慢。
我怀疑减速是浏览器(chrome)必须调整图像大小。
在我用70张图像进行的测试中,我将所有这些图像加载到浏览器中,在加载完所有内容后,滚动性能很慢,前几次我在页面上下滚动,之后就很顺利。
这些图像大约3,000像素乘2,000。我将它们调整为200像素长以显示它们。
加快这一过程的最佳方法是什么?
答案 0 :(得分:1)
我前段时间遇到同样的问题(为摄影师服务时,使用角度)。
问题与RxJS或角度有关,而不是浏览器本身 - 它没有针对以这种方式显示大量图像进行优化。
首先,如果您需要显示大量图像(无论是本地文件还是远程文件):
trackVisibility
,只有在可见时才会显示图片。关于从本地文件显示图像,事情变得更加复杂:
在您的情况下,您将文件作为数据网址加载,并且存在一个问题:您提到的每个3 MB的70个图像将消耗至少2.1 Gb的RAM(实际上更多,并且不经意地会影响性能)
首先建议 - 如果您可以:不使用数据网址,请在不再需要时使用URL.createObjectURL并使用URL.revokeObjectURL。
第二:如果你只需要缩略图 - 在显示之前在本地(使用画布)调整图像大小。如果对你来说很重要,那么抗锯齿就会出现问题 - 请看一下这里描述的降压技术:Html5 canvas drawImage: how to apply antialiasing如果你支持iOS,那么画布尺寸限制就会出现问题,所以你需要以某种方式检测它。 (这两个问题都在下面的例子中讨论过)
最后一个:如果您需要为大量图像创建缩略图 - 请不要立即执行此操作,而是通过事件循环计划工件(否则在调整图像大小时浏览器不会响应)。并且为了更好的性能:按顺序执行(不是对所有图像并行执行),听起来可能很奇怪 - 但是,它会更快(因为内存消耗太低,同时磁盘读取次数更少)。
总结:
trackVisibility
指令仅显示可见图像您可能会发现有助于实现此目的的库:
关于执行图像缩略图的粗略代码示例(大部分代码都是从工作项目中复制的 - 因此,预计它会起作用。canvasToJpegBlob
和makeThumbnail
刚刚编写并且未经过测试,所以可能是小错误):
function loadImage(imagePath) {
return Rx.Observable.create(function(observer) {
var img = new Image();
img.src = imagePath;
image.onload = function() {
observer.onNext(image);
observer.onCompleted();
}
image.onError = function(err) {
observer.onError(err);
}
});
}
// canvas edge cases detection
var maxDimm = 32000;
var ios5 = false, ios3 = false;
(function() {
if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) {
maxDimm = 8000;
} else {
var canvas = document.createElement('canvas');
canvas.width = 1024 * 3;
canvas.height = 1025;
if (canvas.toDataURL('image/jpeg') === 'data:,') {
ios3 = true;
} else {
canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1025;
if (canvas.toDataURL('image/jpeg') === 'data:,') {
ios5 = true;
}
}
}
}());
function stepDown(src, width, height) {
var
steps,
resultCanvas = document.createElement('canvas'),
srcWidth = src.width,
srcHeight = src.height,
context;
resultCanvas.width = width;
resultCanvas.height = height;
if ((srcWidth / width) > (srcHeight / height)) {
steps = Math.ceil(Math.log(srcWidth / width) / Math.log(2));
} else {
steps = Math.ceil(Math.log(srcHeight / height) / Math.log(2));
}
if (steps <= 1) {
context = resultCanvas.getContext('2d');
context.drawImage(src, 0, 0, width, height);
} else {
var tmpCanvas = document.createElement('canvas');
var
currentWidth = width * Math.pow(2, steps - 1),
currentHeight = height * Math.pow(2, steps - 1),
newWidth = currentWidth,
newHeight = currentHeight;
if (ios3 && currentWidth * currentHeight > 3 * 1024 * 1024) {
newHeight = 1024 * Math.sqrt(3 * srcHeight / srcWidth);
newWidth = newHeight * srcWidth / srcHeight;
} else {
if (ios5 && currentWidth * currentHeight > 5 * 1024 * 1024) {
newHeight = 1024 * Math.sqrt(5 * srcHeight / srcWidth);
newWidth = newHeight * srcWidth / srcHeight;
} else {
if (currentWidth > maxDimm || currentHeight > maxDimm) {
if (currentHeight > currentWidth) {
newHeight = maxDimm;
newWidth = maxDimm * currentWidth / currentHeight;
} else {
newWidth = maxDimm;
newHeight = maxDimm * currentWidth / currentHeight;
}
}
}
}
currentWidth = newWidth;
currentHeight = newHeight;
if ((currentWidth / width) > (currentHeight / height)) {
steps = Math.ceil(Math.log(currentWidth / width) / Math.log(2));
} else {
steps = Math.ceil(Math.log(currentHeight / height) / Math.log(2));
}
context = tmpCanvas.getContext('2d');
tmpCanvas.width = Math.ceil(currentWidth);
tmpCanvas.height = Math.ceil(currentHeight);
context.drawImage(src, 0, 0, srcWidth, srcHeight, 0, 0, currentWidth, currentHeight);
while (steps > 1) {
newWidth = currentWidth * 0.5;
newHeight = currentHeight * 0.5;
context.drawImage(tmpCanvas, 0, 0, currentWidth, currentHeight, 0, 0, newWidth, newHeight);
steps -= 1;
currentWidth = newWidth;
currentHeight = newHeight;
}
context = resultCanvas.getContext('2d');
context.drawImage(tmpCanvas, 0, 0, currentWidth, currentHeight, 0, 0, width, height);
}
return resultCanvas;
}
function canvasToJpegBlob(canvas) {
return Rx.Observable.create(function(observer) {
try {
canvas.toBlob(function(blob) {
observer.onNext(blob);
observer.onCompleted();
}, 'image/jpeg');
} catch (err) {
observer.onError(err);
}
});
}
function makeThumbnail(file) {
return Observable.defer(()=> {
const fileUrl = URL.createObjectURL(file);
return loadImage(fileUrl)
.map(image => {
const width = 200;
const height = image.height * width / image.width;
const thumbnailCanvas = stepDown(image, width, height);
URL.revokeObjectURL(fileUrl);
return thubnailCanvas;
})
.flatMap(canvasToJpegBlob)
.map(canvasBlob=>URL.createObjectURL(canvasBlob))
.map(thumbnailUrl => {
return {
file,
thumbnailUrl
}
})
});
}