// File: shirat74[P]resample/PNGImage.cc
// Function: PNGImage::save(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) const
int
PNGImage::save (const std::string filename) const
{
  FILE       *fp;
  png_structp png_ptr;
  png_infop   png_info_ptr;
  png_byte    color_type = PNG_COLOR_TYPE_RGB;

  fp = fopen(filename.c_str(), FOPEN_WBIN_MODE);
  if(!fp)
    return -1;

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL ||
      (png_info_ptr = png_create_info_struct(png_ptr)) == NULL) {
    if (png_ptr)
      png_destroy_read_struct(&png_ptr, NULL, NULL);
    return -1;
  }

#if PNG_LIBPNG_VER >= 10603
  // ignore possibly incorrect CMF bytes
  png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
#endif

  switch (getNComps()) {
  case 1:
    color_type = PNG_COLOR_TYPE_GRAY;
    break;
  case 2:
    color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
    break;
  case 3:
    color_type = PNG_COLOR_TYPE_RGB;
    break;
  case 4:
    color_type = PNG_COLOR_TYPE_RGB_ALPHA;
    break;
  }
  // Inititializing file IO.
  png_init_io(png_ptr, fp);
  // Write header (8 bit colour depth)
  png_set_IHDR(png_ptr, png_info_ptr, getWidth(), getHeight(),
               getBPC(), // BPC of original image data
               color_type,
               PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // Write colorspace related information.
  switch (colorSpaceType) {
  case png_colorspace_gamma_only:
   png_set_gAMA(png_ptr, png_info_ptr, 1.0 / colorSpace.gamma);
   break;
  case png_colorspace_calibrated:
    if (colorSpace.hasGamma)
      png_set_gAMA(png_ptr, png_info_ptr, 1.0 / colorSpace.gamma);
    png_set_cHRM(png_ptr, png_info_ptr,
                 colorSpace.calRGB.xw, colorSpace.calRGB.yw,
                 colorSpace.calRGB.xr, colorSpace.calRGB.yr,
                 colorSpace.calRGB.xg, colorSpace.calRGB.yg,
                 colorSpace.calRGB.xb, colorSpace.calRGB.yb);
    break;
  case png_colorspace_srgb:
    png_set_sRGB(png_ptr, png_info_ptr, colorSpace.sRGB);
    break;
  case png_colorspace_iccp:
    if (colorSpace.ICCP.profile.size() > 0) {
      png_set_iCCP(png_ptr, png_info_ptr,
                   colorSpace.ICCP.name.c_str(),
                   PNG_COMPRESSION_TYPE_DEFAULT,
                   colorSpace.ICCP.profile.data(),
                   colorSpace.ICCP.profile.size());
    }
    break;
  default:
    assert(colorSpaceType == png_colorspace_device);
    break;
  }
  // Resolution convert ppi to pix-per-meter
  png_set_pHYs(png_ptr, png_info_ptr,
               (dpi_x * 10000 + 127) / 254, // add 127 to round to nearest int.
               (dpi_y * 10000 + 127) / 254,
               PNG_RESOLUTION_METER);

  png_write_info(png_ptr, png_info_ptr);

  // Write raster image body.
  png_bytep row = new png_byte[getWidth() * (getBPC() / 8) * getNComps()];
  if (getBPC() == 8) {
    for (int32_t j = 0; j < getHeight(); j++) {
      for (int32_t i = 0; i < getWidth(); i++) {
        Color pixel = getPixel(i, j);
        for (int c = 0; c < getNComps(); c++) {
          row[getNComps() * i + c] = 255 * ((float) pixel.v[c] / 65535.) + .5;
        }
      }
      png_write_row(png_ptr, row);
    }
  } else {
    for (int32_t j = 0; j < getHeight(); j++) {
      for (int32_t i = 0; i < getWidth(); i++) {
        Color   pixel = getPixel(i, j);
        int32_t pos   = 2 * getNComps() * i;
        for (int c = 0; c < getNComps(); c++) {
          uint16_t val = pixel.v[c];
          row[pos + 2 * c] = (val >> 8) & 0xff;
          row[pos + 2 * c + 1] =  val & 0xff;
        }
      }
      png_write_row(png_ptr, row);
    }
  }
  delete row;

  png_write_end(png_ptr, NULL);
  if (png_info_ptr)
    png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
  if (png_ptr)
    png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
  fclose(fp);

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movq %rsi, -0xb0(%rbp)
movq %rdi, %rax
movq -0xb0(%rbp), %rdi
movq %rax, -0x10(%rbp)
movq %rdi, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xa8(%rbp)
movb $0x2, -0x31(%rbp)
callq 0x3140
movq %rax, %rdi
leaq 0x835d(%rip), %rsi      # 0xd05f
callq 0x33e0
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x4d1e
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x54be
leaq 0x8333(%rip), %rdi      # 0xd058
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rsi
movq %rcx, %rdx
callq 0x3100
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x4d52
movq -0x28(%rbp), %rdi
callq 0x34e0
movq %rax, -0x30(%rbp)
cmpq $0x0, %rax
jne 0x4d75
cmpq $0x0, -0x28(%rbp)
je 0x4d69
leaq -0x28(%rbp), %rdi
xorl %eax, %eax
movl %eax, %edx
movq %rdx, %rsi
callq 0x31e0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x54be
movq -0x28(%rbp), %rdi
movl $0x2, %esi
movl $0x3, %edx
callq 0x3470
movq -0xa8(%rbp), %rdi
callq 0x5690
movsbl %al, %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0xb8(%rbp)
subl $0x3, %eax
ja 0x4dd4
movq -0xb8(%rbp), %rax
leaq 0x8283(%rip), %rcx      # 0xd038
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x0, -0x31(%rbp)
jmp 0x4dd4
movb $0x4, -0x31(%rbp)
jmp 0x4dd4
movb $0x2, -0x31(%rbp)
jmp 0x4dd4
movb $0x6, -0x31(%rbp)
movq -0x28(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x3570
movq -0xa8(%rbp), %rdi
movq -0x28(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0xd0(%rbp)
callq 0x56b0
movq -0xa8(%rbp), %rdi
movl %eax, -0xc8(%rbp)
callq 0x56c0
movq -0xa8(%rbp), %rdi
movl %eax, -0xc4(%rbp)
callq 0x56e0
movq -0xd8(%rbp), %rdi
movq -0xd0(%rbp), %rsi
movl -0xc8(%rbp), %edx
movl -0xc4(%rbp), %ecx
movsbl %al, %r8d
movzbl -0x31(%rbp), %r9d
movq %rsp, %rax
movl $0x0, 0x10(%rax)
movl $0x0, 0x8(%rax)
movl $0x0, (%rax)
callq 0x34d0
movq -0xa8(%rbp), %rax
movl 0x88(%rax), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0xc0(%rbp)
subl $0x3, %eax
ja 0x5038
movq -0xc0(%rbp), %rax
leaq 0x81b3(%rip), %rcx      # 0xd048
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0xa8(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movss 0x60(%rax), %xmm0
cvtss2sd %xmm0, %xmm1
movsd 0x816a(%rip), %xmm0     # 0xd028
divsd %xmm1, %xmm0
callq 0x3500
jmp 0x506b
movq -0xa8(%rbp), %rax
testb $0x1, 0x84(%rax)
je 0x4f05
movq -0xa8(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movss 0x60(%rax), %xmm0
cvtss2sd %xmm0, %xmm1
movsd 0x812c(%rip), %xmm0     # 0xd028
divsd %xmm1, %xmm0
callq 0x3500
movq -0xa8(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movss 0x64(%rax), %xmm0
cvtss2sd %xmm0, %xmm0
movss 0x68(%rax), %xmm1
cvtss2sd %xmm1, %xmm1
movss 0x6c(%rax), %xmm2
cvtss2sd %xmm2, %xmm2
movss 0x70(%rax), %xmm3
cvtss2sd %xmm3, %xmm3
movss 0x74(%rax), %xmm4
cvtss2sd %xmm4, %xmm4
movss 0x78(%rax), %xmm5
cvtss2sd %xmm5, %xmm5
movss 0x7c(%rax), %xmm6
cvtss2sd %xmm6, %xmm6
movss 0x80(%rax), %xmm7
cvtss2sd %xmm7, %xmm7
callq 0x3560
jmp 0x506b
movq -0xa8(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movsbl 0x20(%rax), %edx
callq 0x3180
jmp 0x506b
movq -0xa8(%rbp), %rdi
addq $0x20, %rdi
addq $0x8, %rdi
addq $0x20, %rdi
callq 0x5700
cmpq $0x0, %rax
jbe 0x5036
movq -0xa8(%rbp), %rdi
movq -0x28(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0xf0(%rbp)
addq $0x20, %rdi
addq $0x8, %rdi
callq 0x3140
movq -0xa8(%rbp), %rdi
movq %rax, -0xe8(%rbp)
addq $0x20, %rdi
addq $0x8, %rdi
addq $0x20, %rdi
callq 0x5720
movq -0xa8(%rbp), %rdi
movq %rax, -0xe0(%rbp)
addq $0x20, %rdi
addq $0x8, %rdi
addq $0x20, %rdi
callq 0x5700
movq -0xf8(%rbp), %rdi
movq -0xf0(%rbp), %rsi
movq -0xe8(%rbp), %rdx
movq -0xe0(%rbp), %r8
movl %eax, %r9d
xorl %ecx, %ecx
callq 0x3280
jmp 0x506b
movq -0xa8(%rbp), %rax
cmpl $0x0, 0x88(%rax)
jne 0x504a
jmp 0x5069
leaq 0x8010(%rip), %rdi      # 0xd061
leaq 0x8031(%rip), %rsi      # 0xd089
movl $0xe4, %edx
leaq 0x8031(%rip), %rcx      # 0xd095
callq 0x3220
jmp 0x506b
movq -0xa8(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movss 0x8c(%rax), %xmm4
movss 0x90(%rax), %xmm0
movss 0x7f8a(%rip), %xmm3     # 0xd01c
mulss %xmm3, %xmm4
movss 0x7f82(%rip), %xmm2     # 0xd020
addss %xmm2, %xmm4
movss 0x7f7a(%rip), %xmm1     # 0xd024
divss %xmm1, %xmm4
cvttss2si %xmm4, %rax
movl %eax, %edx
mulss %xmm3, %xmm0
addss %xmm2, %xmm0
divss %xmm1, %xmm0
cvttss2si %xmm0, %rax
movl %eax, %ecx
movl $0x1, %r8d
callq 0x3550
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x3200
movq -0xa8(%rbp), %rdi
callq 0x56b0
movq -0xa8(%rbp), %rdi
movl %eax, -0x100(%rbp)
callq 0x56e0
movq -0xa8(%rbp), %rdi
movsbl %al, %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl -0x100(%rbp), %eax
imull %ecx, %eax
movl %eax, -0xfc(%rbp)
callq 0x5690
movb %al, %cl
movl -0xfc(%rbp), %eax
movsbl %cl, %ecx
imull %ecx, %eax
movslq %eax, %rdi
callq 0x3040
movq -0xa8(%rbp), %rdi
movq %rax, -0x40(%rbp)
callq 0x56e0
movsbl %al, %eax
cmpl $0x8, %eax
jne 0x52c1
movl $0x0, -0x44(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x44(%rbp), %eax
movl %eax, -0x104(%rbp)
callq 0x56c0
movl %eax, %ecx
movl -0x104(%rbp), %eax
cmpl %ecx, %eax
jge 0x52bc
movl $0x0, -0x48(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x48(%rbp), %eax
movl %eax, -0x108(%rbp)
callq 0x56b0
movl %eax, %ecx
movl -0x108(%rbp), %eax
cmpl %ecx, %eax
jge 0x52a1
movq -0xa8(%rbp), %rdi
movl -0x48(%rbp), %esi
movl -0x44(%rbp), %edx
callq 0x3e30
movl %edx, -0x60(%rbp)
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x54(%rbp)
movw -0x60(%rbp), %ax
movw %ax, -0x4c(%rbp)
movb -0x5e(%rbp), %al
movb %al, -0x4a(%rbp)
movl $0x0, -0x6c(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x6c(%rbp), %eax
movl %eax, -0x10c(%rbp)
callq 0x5690
movb %al, %cl
movl -0x10c(%rbp), %eax
movsbl %cl, %ecx
cmpl %ecx, %eax
jge 0x5291
movq -0xa8(%rbp), %rdi
movslq -0x6c(%rbp), %rax
movzwl -0x54(%rbp,%rax,2), %eax
cvtsi2ss %eax, %xmm0
cvtss2sd %xmm0, %xmm0
movsd 0x7de2(%rip), %xmm1     # 0xd010
divsd %xmm1, %xmm0
movsd 0x7dce(%rip), %xmm1     # 0xd008
mulsd %xmm1, %xmm0
movsd 0x7dea(%rip), %xmm1     # 0xd030
addsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, -0x119(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x118(%rbp)
callq 0x5690
movb -0x119(%rbp), %dl
movb %al, %cl
movq -0x118(%rbp), %rax
movsbl %cl, %ecx
imull -0x48(%rbp), %ecx
addl -0x6c(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x51e6
jmp 0x5293
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x518b
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x3190
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x515f
jmp 0x544d
movl $0x0, -0x70(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x70(%rbp), %eax
movl %eax, -0x120(%rbp)
callq 0x56c0
movl %eax, %ecx
movl -0x120(%rbp), %eax
cmpl %ecx, %eax
jge 0x544b
movl $0x0, -0x74(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x74(%rbp), %eax
movl %eax, -0x124(%rbp)
callq 0x56b0
movl %eax, %ecx
movl -0x124(%rbp), %eax
cmpl %ecx, %eax
jge 0x5430
movq -0xa8(%rbp), %rdi
movl -0x74(%rbp), %esi
movl -0x70(%rbp), %edx
callq 0x3e30
movq -0xa8(%rbp), %rdi
movl %edx, -0x88(%rbp)
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0x80(%rbp)
movw -0x88(%rbp), %ax
movw %ax, -0x78(%rbp)
movb -0x86(%rbp), %al
movb %al, -0x76(%rbp)
callq 0x5690
movsbl %al, %eax
shll %eax
imull -0x74(%rbp), %eax
movl %eax, -0x94(%rbp)
movl $0x0, -0x98(%rbp)
movq -0xa8(%rbp), %rdi
movl -0x98(%rbp), %eax
movl %eax, -0x128(%rbp)
callq 0x5690
movb %al, %cl
movl -0x128(%rbp), %eax
movsbl %cl, %ecx
cmpl %ecx, %eax
jge 0x5420
movslq -0x98(%rbp), %rax
movw -0x80(%rbp,%rax,2), %ax
movw %ax, -0x9a(%rbp)
movzwl -0x9a(%rbp), %eax
sarl $0x8, %eax
andl $0xff, %eax
movb %al, %dl
movq -0x40(%rbp), %rax
movl -0x94(%rbp), %ecx
movl -0x98(%rbp), %esi
shll %esi
addl %esi, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movzwl -0x9a(%rbp), %eax
andl $0xff, %eax
movb %al, %dl
movq -0x40(%rbp), %rax
movl -0x94(%rbp), %ecx
movl -0x98(%rbp), %esi
shll %esi
addl %esi, %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
jmp 0x537c
jmp 0x5422
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x52f4
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x3190
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0x52c8
jmp 0x544d
movq -0x40(%rbp), %rax
movq %rax, -0x130(%rbp)
cmpq $0x0, %rax
je 0x546f
movq -0x130(%rbp), %rdi
movl $0x1, %esi
callq 0x3340
movq -0x28(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x3350
cmpq $0x0, -0x30(%rbp)
je 0x549a
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movl $0xffff, %edx           # imm = 0xFFFF
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
callq 0x33c0
cmpq $0x0, -0x28(%rbp)
je 0x54ae
leaq -0x28(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x3270
movq -0x20(%rbp), %rdi
callq 0x3320
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
nopw (%rax,%rax)