// File: cloudinary[P]fuif/transform/dct.h
// Function: inv_DCT(Image&, std::vector<int, std::allocator<int>>&)
bool inv_DCT(Image &input, std::vector<int> &parameters) {
    if (!parameters.size()) default_DCT_parameters(parameters,input);
    int beginc = input.nb_meta_channels + parameters[0];
    int endc = input.nb_meta_channels + parameters[1];
    int nb_channels = endc-beginc+1;
    int offset = input.channel.size() - 63*nb_channels;

    if (offset <= endc) {
        e_printf("Invalid number of channels to apply inverse DCT.\n");
        return false;
    }
    v_printf(3,"Undoing DCT on channels %i..%i with AC coefficients in channels %i..%i\n",beginc,endc,offset,offset+63*nb_channels-1);


    std::vector<std::vector<int>> ordering;
    std::vector<int> comp;
    std::vector<int> coeff;
    default_DCT_scanscript(nb_channels,ordering,comp,coeff);

    for (int c=beginc; c<=endc; c++) {
        int bw = input.channel[c-beginc+offset].w; // consider first AC, in case we did repeated DCT (TODO: try repeated DCT to see if it even makes sense)
        int bh = input.channel[c-beginc+offset].h;
        if (input.channel[c].w < bw) bw = input.channel[c].w;
        if (input.channel[c].h < bh) bh = input.channel[c].h;

        v_printf(3,"  Channel %i : %ix%i image from %ix%i blocks\n",c,bw*8,bh*8,bw,bh);
        Channel outch(bw*8,bh*8,0,0);
        outch.component = input.channel[c].component;
        outch.hshift = input.channel[c].hshift - 3;
        outch.vshift = input.channel[c].vshift - 3;
        outch.hcshift = input.channel[c].hcshift - 3;
        outch.vcshift = input.channel[c].hcshift - 3;
        float DCoffset = (input.maxval + 1.0) * 4.0;
        for (int by=0; by<bh; by++) {
          for (int bx=0; bx<bw; bx++) {
            double block[64];
            block[0] = input.channel[c].value(by,bx) + DCoffset;
            for (int i=1; i<64; i++) block[i] = input.channel[offset-nb_channels+ ordering[c-beginc][jpeg_zigzag[i]]].value(by,bx);
            ComputeBlockIDCTDouble(block);
            for (int y=0; y<8; y++)
            for (int x=0; x<8; x++) outch.value(by*8+y, bx*8+x) = round(block[y*8+x]);
          }
        }
        input.channel[c] = outch;
    }
    input.channel.erase(input.channel.begin()+offset,input.channel.begin()+offset+nb_channels*63);
    return true;
}

// Assembly:
subq $0x3b8, %rsp            # imm = 0x3B8
movq %rdi, 0x3a8(%rsp)
movq %rsi, 0x3a0(%rsp)
movq 0x3a0(%rsp), %rdi
callq 0x4d50
cmpq $0x0, %rax
jne 0x8a3f
movq 0x3a0(%rsp), %rdi
movq 0x3a8(%rsp), %rsi
callq 0x84f0
movq 0x3a8(%rsp), %rax
movl 0x6c(%rax), %eax
movl %eax, 0x88(%rsp)
movq 0x3a0(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x12190
movq %rax, %rcx
movl 0x88(%rsp), %eax
addl (%rcx), %eax
movl %eax, 0x39c(%rsp)
movq 0x3a8(%rsp), %rax
movl 0x6c(%rax), %eax
movl %eax, 0x8c(%rsp)
movq 0x3a0(%rsp), %rdi
movl $0x1, %esi
callq 0x12190
movq %rax, %rcx
movl 0x8c(%rsp), %eax
addl (%rcx), %eax
movl %eax, 0x398(%rsp)
movl 0x398(%rsp), %eax
subl 0x39c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x394(%rsp)
movq 0x3a8(%rsp), %rdi
callq 0x4b80
imull $0x3f, 0x394(%rsp), %ecx
movslq %ecx, %rcx
subq %rcx, %rax
movl %eax, 0x390(%rsp)
movl 0x390(%rsp), %eax
cmpl 0x398(%rsp), %eax
jg 0x8b11
leaq 0x3dce6(%rip), %rdi     # 0x467e3
movb $0x0, %al
callq 0x3a670
movb $0x0, 0x3b7(%rsp)
jmp 0x9263
movl 0x39c(%rsp), %edx
movl 0x398(%rsp), %ecx
movl 0x390(%rsp), %r8d
movl 0x394(%rsp), %eax
movl %eax, %edi
shll $0x6, %edi
subl %eax, %edi
movl %r8d, %eax
movl %edi, %esi
leal -0x1(%rax,%rsi), %r9d
leaq 0x3dccf(%rip), %rsi     # 0x46815
xorl %eax, %eax
movl $0x3, %edi
callq 0x3a770
leaq 0x378(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x125d0
leaq 0x360(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x125e0
leaq 0x348(%rsp), %rdi
movq %rdi, 0x80(%rsp)
callq 0x125e0
movq 0x70(%rsp), %rsi
movq 0x78(%rsp), %rdx
movq 0x80(%rsp), %rcx
movl 0x394(%rsp), %edi
callq 0x8180
jmp 0x8bab
movl 0x39c(%rsp), %eax
movl %eax, 0x338(%rsp)
movl 0x338(%rsp), %eax
cmpl 0x398(%rsp), %eax
jg 0x9122
movq 0x3a8(%rsp), %rdi
movl 0x338(%rsp), %eax
subl 0x39c(%rsp), %eax
addl 0x390(%rsp), %eax
movslq %eax, %rsi
callq 0x4ba0
movl 0x18(%rax), %eax
movl %eax, 0x334(%rsp)
movq 0x3a8(%rsp), %rdi
movl 0x338(%rsp), %eax
subl 0x39c(%rsp), %eax
addl 0x390(%rsp), %eax
movslq %eax, %rsi
callq 0x4ba0
movl 0x1c(%rax), %eax
movl %eax, 0x330(%rsp)
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x18(%rax), %eax
cmpl 0x334(%rsp), %eax
jge 0x8c86
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x18(%rax), %eax
movl %eax, 0x334(%rsp)
jmp 0x8c86
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x340(%rsp)
movl %eax, 0x33c(%rsp)
jmp 0x923a
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x1c(%rax), %eax
cmpl 0x330(%rsp), %eax
jge 0x8cc6
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x1c(%rax), %eax
movl %eax, 0x330(%rsp)
movl 0x338(%rsp), %edx
movl 0x334(%rsp), %r9d
movl %r9d, %ecx
shll $0x3, %ecx
movl 0x330(%rsp), %esi
movl %esi, %r8d
shll $0x3, %r8d
movq %rsp, %rax
movl %esi, (%rax)
leaq 0x3db68(%rip), %rsi     # 0x4685d
xorl %eax, %eax
movl $0x3, %edi
callq 0x3a770
jmp 0x8d03
movl 0x334(%rsp), %esi
shll $0x3, %esi
movl 0x330(%rsp), %edx
shll $0x3, %edx
movq %rsp, %rax
movl $0x0, 0x18(%rax)
movl $0x0, 0x10(%rax)
movl $0x0, 0x8(%rax)
movl $0x0, (%rax)
leaq 0x2f0(%rsp), %rdi
xorl %r8d, %r8d
movl $0x1, %r9d
movl %r8d, %ecx
callq 0x12200
jmp 0x8d50
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x3c(%rax), %eax
movl %eax, 0x32c(%rsp)
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x2c(%rax), %eax
subl $0x3, %eax
movl %eax, 0x31c(%rsp)
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x30(%rax), %eax
subl $0x3, %eax
movl %eax, 0x320(%rsp)
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x34(%rax), %eax
subl $0x3, %eax
movl %eax, 0x324(%rsp)
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movl 0x34(%rax), %eax
subl $0x3, %eax
movl %eax, 0x328(%rsp)
movq 0x3a8(%rsp), %rax
cvtsi2sdl 0x60(%rax), %xmm0
movsd 0x3d3dc(%rip), %xmm1    # 0x461e8
addsd %xmm1, %xmm0
movsd 0x3d3c8(%rip), %xmm1    # 0x461e0
mulsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x2ec(%rsp)
movl $0x0, 0x2e8(%rsp)
movl 0x2e8(%rsp), %eax
cmpl 0x330(%rsp), %eax
jge 0x90d8
movl $0x0, 0x2e4(%rsp)
movl 0x2e4(%rsp), %eax
cmpl 0x334(%rsp), %eax
jge 0x90c0
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movq %rax, %rdi
movl 0x2e8(%rsp), %esi
movl 0x2e4(%rsp), %edx
callq 0x12110
movq %rax, 0x68(%rsp)
jmp 0x8e99
movq 0x68(%rsp), %rax
movswl (%rax), %eax
cvtsi2ss %eax, %xmm0
addss 0x2ec(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0xe0(%rsp)
movl $0x1, 0xdc(%rsp)
cmpl $0x40, 0xdc(%rsp)
jge 0x8fbe
movq 0x3a8(%rsp), %rax
movq %rax, 0x50(%rsp)
movl 0x390(%rsp), %eax
movl 0x394(%rsp), %ecx
subl %ecx, %eax
movl %eax, 0x5c(%rsp)
movl 0x338(%rsp), %eax
movl 0x39c(%rsp), %ecx
subl %ecx, %eax
movslq %eax, %rsi
leaq 0x378(%rsp), %rdi
callq 0x12540
movq %rax, %rdi
movslq 0xdc(%rsp), %rcx
leaq 0x3d539(%rip), %rax     # 0x46460
movslq (%rax,%rcx,4), %rsi
callq 0x12190
movq 0x50(%rsp), %rdi
movq %rax, %rcx
movl 0x5c(%rsp), %eax
movl (%rcx), %ecx
addl %ecx, %eax
movslq %eax, %rsi
callq 0x4ba0
movq %rax, %rdi
movl 0x2e8(%rsp), %esi
movl 0x2e4(%rsp), %edx
callq 0x12110
movq %rax, 0x60(%rsp)
jmp 0x8f65
movq 0x60(%rsp), %rax
movswl (%rax), %eax
cvtsi2sd %eax, %xmm0
movslq 0xdc(%rsp), %rax
movsd %xmm0, 0xe0(%rsp,%rax,8)
movl 0xdc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xdc(%rsp)
jmp 0x8ec6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x340(%rsp)
movl %eax, 0x33c(%rsp)
leaq 0x2f0(%rsp), %rdi
callq 0x12380
jmp 0x923a
leaq 0xe0(%rsp), %rdi
callq 0x8160
jmp 0x8fcd
movl $0x0, 0xd8(%rsp)
cmpl $0x8, 0xd8(%rsp)
jge 0x90a8
movl $0x0, 0xd4(%rsp)
cmpl $0x8, 0xd4(%rsp)
jge 0x9090
movl 0xd8(%rsp), %eax
movl 0xd4(%rsp), %edx
movl %eax, %ecx
movq %rcx, 0x30(%rsp)
movl %edx, %eax
movq %rax, 0x38(%rsp)
leal (%rax,%rcx,8), %eax
cltq
movsd 0xe0(%rsp,%rax,8), %xmm0
callq 0x3180
movq 0x30(%rsp), %rcx
movq 0x38(%rsp), %rax
cvttsd2si %xmm0, %edx
movw %dx, 0x46(%rsp)
movl 0x2e8(%rsp), %esi
movl %esi, %edx
leal (%rcx,%rdx,8), %esi
movl 0x2e4(%rsp), %edx
movl %edx, %ecx
leal (%rax,%rcx,8), %edx
leaq 0x2f0(%rsp), %rdi
callq 0x12110
movq %rax, 0x48(%rsp)
jmp 0x906d
movq 0x48(%rsp), %rax
movw 0x46(%rsp), %cx
movw %cx, (%rax)
movl 0xd4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd4(%rsp)
jmp 0x8ff1
jmp 0x9092
movl 0xd8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd8(%rsp)
jmp 0x8fd8
jmp 0x90aa
movl 0x2e4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2e4(%rsp)
jmp 0x8e53
jmp 0x90c2
movl 0x2e8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2e8(%rsp)
jmp 0x8e34
movq 0x3a8(%rsp), %rdi
movslq 0x338(%rsp), %rsi
callq 0x4ba0
movq %rax, %rdi
leaq 0x2f0(%rsp), %rsi
callq 0x12390
jmp 0x90ff
leaq 0x2f0(%rsp), %rdi
callq 0x12380
movl 0x338(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x338(%rsp)
jmp 0x8bb9
movq 0x3a8(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x127d0
movq %rax, 0xb8(%rsp)
movslq 0x390(%rsp), %rsi
leaq 0xb8(%rsp), %rdi
callq 0x12800
movq %rax, 0xc0(%rsp)
leaq 0xc8(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x12840
movq 0x3a8(%rsp), %rdi
callq 0x127d0
movq %rax, 0x98(%rsp)
movslq 0x390(%rsp), %rsi
leaq 0x98(%rsp), %rdi
callq 0x12800
movq %rax, 0xa0(%rsp)
movl 0x394(%rsp), %ecx
movl %ecx, %eax
shll $0x6, %eax
subl %ecx, %eax
movslq %eax, %rsi
leaq 0xa0(%rsp), %rdi
callq 0x12800
movq %rax, 0xa8(%rsp)
leaq 0xb0(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x12840
movq 0x20(%rsp), %rdi
movq 0xc8(%rsp), %rsi
movq 0xb0(%rsp), %rdx
callq 0x12730
movq %rax, 0x28(%rsp)
jmp 0x91fc
movq 0x28(%rsp), %rax
movq %rax, 0x90(%rsp)
movb $0x1, 0x3b7(%rsp)
leaq 0x348(%rsp), %rdi
callq 0x54f0
leaq 0x360(%rsp), %rdi
callq 0x54f0
leaq 0x378(%rsp), %rdi
callq 0x126d0
jmp 0x9263
leaq 0x348(%rsp), %rdi
callq 0x54f0
leaq 0x360(%rsp), %rdi
callq 0x54f0
leaq 0x378(%rsp), %rdi
callq 0x126d0
jmp 0x9274
movb 0x3b7(%rsp), %al
andb $0x1, %al
addq $0x3b8, %rsp            # imm = 0x3B8
retq
movq 0x340(%rsp), %rdi
callq 0x36a0
nopw %cs:(%rax,%rax)