// File: misohena[P]drawstars/./image.h
// Function: bool writeBMPFile<Image<ColorRGB<double>>>(char const*, Image<ColorRGB<double>> const&)
bool writeBMPFile(const char *filename, const ImageT &image)
{
    // Header
    const unsigned int fileHeaderSize = 14;
    const unsigned int infoHeaderSize = 40;
    const unsigned int width = image.width();
    const unsigned int height = image.height();
    const unsigned int pixelSize = 3;
    const unsigned int lineSize = pixelSize * width;
    const unsigned int lineStride = (lineSize + 3) & ~3;
    const unsigned int imageSize = lineStride * height;
    const unsigned int offBits = fileHeaderSize + infoHeaderSize;
    const unsigned int fileSize = offBits + imageSize;
#define word(v) (unsigned char)((v)&255), (unsigned char)((v)>>8&255)
#define dword(v) word(v), word(v>>16)
    const unsigned char header[] = {
        // BITMAPFILEHEADER
        'B', 'M', dword(fileSize), 0, 0, 0, 0, dword(offBits),
        // BITMAPINFOHEADER
        dword(infoHeaderSize),
        dword(width), dword(height), word(1), word(8*pixelSize),
        dword(0),
        dword(imageSize),
        dword(0), dword(0), dword(0), dword(0)
    };
#undef dword
#undef word

    // Body
    std::unique_ptr<std::uint8_t[]> body(new std::uint8_t[imageSize]);
    for(int y = 0; y < height; ++y){
        auto dst = body.get() + y * lineStride;
        auto src = image.at(0, height - y - 1);//bottom-up
        for(int x = 0; x < width; ++x, ++src, dst += 3){
            using VT = typename ImageT::PixelType::ValueType;
            dst[0] = static_cast<std::uint8_t>(clamp(255*src->b, VT(0), VT(255)));
            dst[1] = static_cast<std::uint8_t>(clamp(255*src->g, VT(0), VT(255)));
            dst[2] = static_cast<std::uint8_t>(clamp(255*src->r, VT(0), VT(255)));
        }
    }

    if(File file = File(filename, "wb")){
        std::fwrite(header, sizeof(header), 1, file);
        std::fwrite(body.get(), imageSize, 1, file);
        return true;
    }
    else{
        return false;
    }
}

// Assembly:
subq $0xe8, %rsp
movq %rdi, 0xd8(%rsp)
movq %rsi, 0xd0(%rsp)
movl $0xe, 0xcc(%rsp)
movl $0x28, 0xc8(%rsp)
movq 0xd0(%rsp), %rdi
callq 0x11c00
movl %eax, 0xc4(%rsp)
movq 0xd0(%rsp), %rdi
callq 0x11c10
movl %eax, 0xc0(%rsp)
movl $0x3, 0xbc(%rsp)
imull $0x3, 0xc4(%rsp), %eax
movl %eax, 0xb8(%rsp)
movl 0xb8(%rsp), %eax
addl $0x3, %eax
andl $-0x4, %eax
movl %eax, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
imull 0xc0(%rsp), %eax
movl %eax, 0xb0(%rsp)
movl $0x36, 0xac(%rsp)
movl 0xb0(%rsp), %eax
addl $0x36, %eax
movl %eax, 0xa8(%rsp)
movb $0x42, 0x70(%rsp)
movb $0x4d, 0x71(%rsp)
movl 0xa8(%rsp), %eax
andl $0xff, %eax
movb %al, 0x72(%rsp)
movl 0xa8(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x73(%rsp)
movl 0xa8(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x74(%rsp)
movl 0xa8(%rsp), %eax
shrl $0x10, %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x75(%rsp)
movb $0x0, 0x76(%rsp)
movb $0x0, 0x77(%rsp)
movb $0x0, 0x78(%rsp)
movb $0x0, 0x79(%rsp)
movb $0x36, 0x7a(%rsp)
movb $0x0, 0x7b(%rsp)
movb $0x0, 0x7c(%rsp)
movb $0x0, 0x7d(%rsp)
movb $0x28, 0x7e(%rsp)
movb $0x0, 0x7f(%rsp)
movb $0x0, 0x80(%rsp)
movb $0x0, 0x81(%rsp)
movl 0xc4(%rsp), %eax
andl $0xff, %eax
movb %al, 0x82(%rsp)
movl 0xc4(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x83(%rsp)
movl 0xc4(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x84(%rsp)
movl 0xc4(%rsp), %eax
shrl $0x10, %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x85(%rsp)
movl 0xc0(%rsp), %eax
andl $0xff, %eax
movb %al, 0x86(%rsp)
movl 0xc0(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x87(%rsp)
movl 0xc0(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x88(%rsp)
movl 0xc0(%rsp), %eax
shrl $0x10, %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x89(%rsp)
movb $0x1, 0x8a(%rsp)
movb $0x0, 0x8b(%rsp)
movb $0x18, 0x8c(%rsp)
movb $0x0, 0x8d(%rsp)
movb $0x0, 0x8e(%rsp)
movb $0x0, 0x8f(%rsp)
movb $0x0, 0x90(%rsp)
movb $0x0, 0x91(%rsp)
movl 0xb0(%rsp), %eax
andl $0xff, %eax
movb %al, 0x92(%rsp)
movl 0xb0(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x93(%rsp)
movl 0xb0(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x94(%rsp)
movl 0xb0(%rsp), %eax
shrl $0x10, %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x95(%rsp)
movb $0x0, 0x96(%rsp)
movb $0x0, 0x97(%rsp)
movb $0x0, 0x98(%rsp)
movb $0x0, 0x99(%rsp)
movb $0x0, 0x9a(%rsp)
movb $0x0, 0x9b(%rsp)
movb $0x0, 0x9c(%rsp)
movb $0x0, 0x9d(%rsp)
movb $0x0, 0x9e(%rsp)
movb $0x0, 0x9f(%rsp)
movb $0x0, 0xa0(%rsp)
movb $0x0, 0xa1(%rsp)
movb $0x0, 0xa2(%rsp)
movb $0x0, 0xa3(%rsp)
movb $0x0, 0xa4(%rsp)
movb $0x0, 0xa5(%rsp)
movl 0xb0(%rsp), %eax
movl %eax, %edi
callq 0x4030
movq %rax, %rsi
leaq 0x68(%rsp), %rdi
callq 0x11c20
movl $0x0, 0x64(%rsp)
movl 0x64(%rsp), %eax
cmpl 0xc0(%rsp), %eax
jae 0xe891
leaq 0x68(%rsp), %rdi
callq 0x11c50
movl 0x64(%rsp), %ecx
imull 0xb4(%rsp), %ecx
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, 0x58(%rsp)
movq 0xd0(%rsp), %rdi
movl 0xc0(%rsp), %edx
subl 0x64(%rsp), %edx
subl $0x1, %edx
xorl %esi, %esi
callq 0x11c80
movq %rax, 0x50(%rsp)
movl $0x0, 0x4c(%rsp)
movl 0x4c(%rsp), %eax
cmpl 0xc4(%rsp), %eax
jae 0xe87f
movq 0x50(%rsp), %rax
movsd 0x10(%rax), %xmm0
movsd 0xf8ba(%rip), %xmm2     # 0x1e060
mulsd %xmm2, %xmm0
xorps %xmm1, %xmm1
callq 0xe9a0
movsd %xmm0, 0x20(%rsp)
jmp 0xe7ba
movsd 0x20(%rsp), %xmm0
cvttsd2si %xmm0, %eax
movb %al, %cl
movq 0x58(%rsp), %rax
movb %cl, (%rax)
movq 0x50(%rsp), %rax
movsd 0x8(%rax), %xmm0
movsd 0xf881(%rip), %xmm2     # 0x1e060
mulsd %xmm2, %xmm0
xorps %xmm1, %xmm1
callq 0xe9a0
movsd %xmm0, 0x18(%rsp)
jmp 0xe7f3
movsd 0x18(%rsp), %xmm0
cvttsd2si %xmm0, %eax
movb %al, %cl
movq 0x58(%rsp), %rax
movb %cl, 0x1(%rax)
movq 0x50(%rsp), %rax
movsd (%rax), %xmm0
movsd 0xf848(%rip), %xmm2     # 0x1e060
mulsd %xmm2, %xmm0
xorps %xmm1, %xmm1
callq 0xe9a0
movsd %xmm0, 0x10(%rsp)
jmp 0xe82c
movsd 0x10(%rsp), %xmm0
cvttsd2si %xmm0, %eax
movb %al, %cl
movq 0x58(%rsp), %rax
movb %cl, 0x2(%rax)
movl 0x4c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4c(%rsp)
movq 0x50(%rsp), %rax
addq $0x18, %rax
movq %rax, 0x50(%rsp)
movq 0x58(%rsp), %rax
addq $0x3, %rax
movq %rax, 0x58(%rsp)
jmp 0xe783
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x40(%rsp)
movl %eax, 0x3c(%rsp)
jmp 0xe980
jmp 0xe881
movl 0x64(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x64(%rsp)
jmp 0xe728
movq 0xd8(%rsp), %rsi
leaq 0xfc0e(%rip), %rdx      # 0x1e4ae
leaq 0x30(%rsp), %rdi
callq 0x11bb0
jmp 0xe8ac
leaq 0x30(%rsp), %rdi
callq 0x11bf0
cmpq $0x0, %rax
je 0xe94b
leaq 0x30(%rsp), %rdi
callq 0x11bf0
movq %rax, %rcx
leaq 0x70(%rsp), %rdi
movl $0x36, %esi
movl $0x1, %edx
callq 0x4670
jmp 0xe8e3
leaq 0x68(%rsp), %rdi
callq 0x11c50
movq %rax, (%rsp)
movl 0xb0(%rsp), %eax
movq %rax, 0x8(%rsp)
leaq 0x30(%rsp), %rdi
callq 0x11bf0
movq (%rsp), %rdi
movq 0x8(%rsp), %rsi
movq %rax, %rcx
movl $0x1, %edx
callq 0x4670
jmp 0xe91f
movb $0x1, 0xe7(%rsp)
movl $0x1, 0x2c(%rsp)
jmp 0xe95b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x40(%rsp)
movl %eax, 0x3c(%rsp)
leaq 0x30(%rsp), %rdi
callq 0x11d20
jmp 0xe980
movb $0x0, 0xe7(%rsp)
movl $0x1, 0x2c(%rsp)
leaq 0x30(%rsp), %rdi
callq 0x11d20
leaq 0x68(%rsp), %rdi
callq 0x11cc0
movb 0xe7(%rsp), %al
andb $0x1, %al
addq $0xe8, %rsp
retq
leaq 0x68(%rsp), %rdi
callq 0x11cc0
movq 0x40(%rsp), %rdi
callq 0x45f0
nopw %cs:(%rax,%rax)
nop