// File: /workspace/github_cpp_makefile_star2_O2/jpbalarini[P]otsus/./framework/CImage.cpp
// Function: CImage::save_PNG(char*, int)
void CImage::save_PNG(char *filename, int bits_per_channel) {
  png_byte color_type;
  png_byte bit_depth;
  png_structp png_ptr;
  png_infop info_ptr;
  png_bytep * row_pointers;

  /* create file */
  FILE *fp = fopen(filename, "wb");
  if (!fp) {
    PRINT_ERROR("File %s could not be opened for writing\n", filename);
    exit(-1);
  }

  /* initialize stuff */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr) {
    PRINT_ERROR("png_create_write_struct failed\n");
    exit(-1);
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    PRINT_ERROR("png_create_info_struct failed\n");
    exit(-1);
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("Error during init_io\n");
    exit(-1);
  }

  png_init_io(png_ptr, fp);

  /* write header */
  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("Error during writing header\n");
    exit(-1);
  }

  bit_depth = bits_per_channel;
  color_type = (this->get_num_channels() == 1 || bit_depth < 8 ?
                PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB);

  int height = this->get_height();
  int width = this->get_width();
  
  png_set_IHDR(png_ptr, info_ptr, this->get_width(), height,
         bit_depth, color_type, PNG_INTERLACE_NONE,
         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  // Create row pointers
  int bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);  
  png_byte *png_buffer = new png_byte[this->Ny * bytes_per_row];
  
  row_pointers = (png_bytep*)png_malloc(png_ptr, this->Ny * sizeof(png_bytep));
  for (int y = 0; y < this->Ny; y++)
    row_pointers[y] = &png_buffer[y * bytes_per_row];

  /* write bytes */
  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("error during writing bytes\n");
    exit(-1);
  }

  int channels = this->get_num_channels();
  
  this->bits = bits_per_channel;

  if (bits_per_channel == 8) {
    for (int ch = 0; ch < channels; ch++) {
      float *orig = this->get_channel(ch);
      for (int y = 0; y < height; y++) {
        for (int x = 0; x < this->get_width(); x++)
          row_pointers[y][x * channels + ch] = orig[width * y + x];
      }
    }
  }

  if (bits_per_channel == 16) {
    float multiplier = (this->bits == 8 ? 256 : 1);
    for (int ch = 0; ch < channels; ch++) {
      float *orig = this->get_channel(ch);
      for (int y = 0; y < height; y++) {
        for (int x = 0; x < this->get_width(); x++) {
          int data = orig[width * y + x] * multiplier;
          int pos = (x * channels + ch) * 2;
          row_pointers[y][pos] = (data & 0xFF00) >> 8;
          row_pointers[y][pos + 1] = (data & 0x00FF);
        }
      }
    }
  }

  png_write_image(png_ptr, row_pointers);

  /* end write */
  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("error during end of write\n");
    exit(-1);
  }

  png_write_end(png_ptr, NULL);
  fclose(fp);

  /* cleanup heap allocation */
  // Free memory
  free(row_pointers);
  delete[] png_buffer;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movl %edx, %r13d
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x2c19(%rip), %rsi      # 0x80ff
movq %rbx, %rdi
callq 0x3320
testq %rax, %rax
je 0x57ff
movq %rax, %r12
leaq 0x2fa4(%rip), %rdi      # 0x84a5
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rsi
movq %rcx, %rdx
callq 0x3130
testq %rax, %rax
je 0x583e
movq %rax, %rbp
movq %rax, %rdi
callq 0x34b0
testq %rax, %rax
je 0x5873
movq %rax, %r15
movq 0x6a59(%rip), %rsi      # 0xbf90
movl $0xc8, %edx
movq %rbp, %rdi
callq 0x32d0
movq %rax, %rdi
callq 0x33d0
testl %eax, %eax
jne 0x58a8
movq %rbp, %rdi
movq %r12, 0x40(%rsp)
movq %r12, %rsi
callq 0x3500
movq 0x6a25(%rip), %rsi      # 0xbf90
movl $0xc8, %edx
movq %rbp, %rdi
callq 0x32d0
movq %rax, %rdi
callq 0x33d0
testl %eax, %eax
jne 0x58dd
xorl %eax, %eax
cmpl $0x1, 0x18(%r14)
movq %r15, %r12
setne %cl
movl %r13d, 0xc(%rsp)
movzbl %r13b, %r8d
movb %cl, %al
addl %eax, %eax
xorl %edx, %edx
cmpl $0x8, %r8d
movl (%r14), %ecx
movl 0x4(%r14), %r15d
movslq %ecx, %rcx
movl %eax, %r9d
cmovbl %edx, %r9d
subq $0x8, %rsp
movq %rcx, 0x18(%rsp)
movl %ecx, %edx
movq %rbp, %rdi
movq %r12, %rsi
movl %r15d, %ecx
pushq $0x0
pushq $0x0
pushq $0x0
callq 0x3470
addq $0x20, %rsp
movq %rbp, %rdi
movq %r12, %rsi
callq 0x31b0
movq %rbp, %rdi
movq %r12, %rsi
callq 0x30b0
movslq 0x4(%r14), %r13
movslq %eax, %r12
movq %r13, %rdi
imulq %r12, %rdi
callq 0x3030
movq %rax, %rbx
movq %r13, %rsi
shlq $0x3, %rsi
movq %rbp, 0x18(%rsp)
movq %rbp, %rdi
callq 0x3480
movq %rax, %r13
movl 0x4(%r14), %eax
testl %eax, %eax
movl $0x0, %ecx
cmovlel %ecx, %eax
movl %ecx, %edx
movq %rbx, 0x38(%rsp)
movq %rbx, %rcx
cmpq %rdx, %rax
je 0x5649
movq %rcx, (%r13,%rdx,8)
incq %rdx
addq %r12, %rcx
jmp 0x5637
movq 0x6940(%rip), %rsi      # 0xbf90
movl $0xc8, %edx
movq 0x18(%rsp), %rdi
callq 0x32d0
movq %rax, %rdi
callq 0x33d0
testl %eax, %eax
jne 0x590f
movslq 0x18(%r14), %r12
movl 0xc(%rsp), %eax
movl %eax, 0x8(%r14)
cmpl $0x10, %eax
je 0x5706
cmpl $0x8, %eax
jne 0x5794
movq %r12, %rax
xorl %edx, %edx
testl %r15d, %r15d
cmovlel %edx, %r15d
testl %eax, %eax
movl %edx, %ecx
cmovgl %eax, %ecx
movl %ecx, %eax
movq %rax, 0x28(%rsp)
movl %r15d, %ebp
movq 0x10(%rsp), %r15
shlq $0x2, %r15
movl %edx, %ebx
cmpq 0x28(%rsp), %rbx
je 0x5794
movl %ebx, %esi
movq %r14, %rdi
callq 0x598a
xorl %r9d, %r9d
movl %r9d, %ecx
cmpq %rbp, %rcx
je 0x5701
movl %r9d, %esi
movq %rbx, %rdx
movslq (%r14), %rdi
cmpq %rdi, %rsi
jge 0x56f9
cvttss2si (%rax,%rsi,4), %edi
movq (%r13,%rcx,8), %r8
movb %dil, (%r8,%rdx)
incq %rsi
addq %r12, %rdx
jmp 0x56db
incq %rcx
addq %r15, %rax
jmp 0x56d0
incq %rbx
jmp 0x56b5
xorl %edx, %edx
testl %r15d, %r15d
cmovlel %edx, %r15d
testl %r12d, %r12d
movl %edx, %ecx
cmovgl %r12d, %ecx
movl %ecx, %eax
movq %rax, 0x30(%rsp)
movl %r15d, %ebx
movq 0x10(%rsp), %r15
shlq $0x2, %r15
addq %r12, %r12
pushq $0x1
popq %rbp
movl %edx, %eax
cmpq 0x30(%rsp), %rax
je 0x5794
movq %rax, 0x20(%rsp)
movl %eax, %esi
movq %r14, %rdi
callq 0x598a
xorl %r9d, %r9d
movl %r9d, %ecx
cmpq %rbx, %rcx
je 0x5786
movl %r9d, %esi
movq %rbp, %rdx
movslq (%r14), %rdi
cmpq %rdi, %rsi
jge 0x577e
cvttss2si (%rax,%rsi,4), %edi
rolw $0x8, %di
movq (%r13,%rcx,8), %r8
movw %di, -0x1(%r8,%rdx)
incq %rsi
addq %r12, %rdx
jmp 0x575a
incq %rcx
addq %r15, %rax
jmp 0x574f
movq 0x20(%rsp), %rax
incq %rax
addq $0x2, %rbp
jmp 0x5733
movq 0x18(%rsp), %rbx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3050
movq 0x67e5(%rip), %rsi      # 0xbf90
movl $0xc8, %edx
movq %rbx, %rdi
callq 0x32d0
movq %rax, %rdi
callq 0x33d0
testl %eax, %eax
jne 0x5941
xorl %eax, %eax
movl %eax, %esi
movq %rbx, %rdi
callq 0x32a0
movq 0x40(%rsp), %rdi
callq 0x3270
movq %r13, %rdi
callq 0x3330
movq 0x38(%rsp), %rdi
callq 0x3380
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x67ba(%rip), %r14      # 0xbfc0
movq (%r14), %rdi
leaq 0x2877(%rip), %rsi      # 0x8087
leaq 0x2ab1(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl %eax, %ebp
movl $0x190, %edx            # imm = 0x190
callq 0x33c0
movq (%r14), %rdi
leaq 0x2ce9(%rip), %rsi      # 0x8518
movq %rbx, %rdx
movl %ebp, %eax
callq 0x33c0
jmp 0x597a
movq 0x677b(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x2838(%rip), %rsi      # 0x8087
leaq 0x2a72(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x198, %edx            # imm = 0x198
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2cd5(%rip), %rdi      # 0x8541
pushq $0x1f
jmp 0x5971
movq 0x6746(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x2803(%rip), %rsi      # 0x8087
leaq 0x2a3d(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x19e, %edx            # imm = 0x19E
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2c2a(%rip), %rdi      # 0x84cb
pushq $0x1e
jmp 0x5971
movq 0x6711(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x27ce(%rip), %rsi      # 0x8087
leaq 0x2a08(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x1a3, %edx            # imm = 0x1A3
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2c8b(%rip), %rdi      # 0x8561
pushq $0x15
jmp 0x5971
movq 0x66dc(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x2799(%rip), %rsi      # 0x8087
leaq 0x29d3(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x1ab, %edx            # imm = 0x1AB
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2c6c(%rip), %rdi      # 0x8577
pushq $0x1c
jmp 0x5971
movq 0x66aa(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x2767(%rip), %rsi      # 0x8087
leaq 0x29a1(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x1c6, %edx            # imm = 0x1C6
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2c57(%rip), %rdi      # 0x8594
pushq $0x1b
jmp 0x5971
movq 0x6678(%rip), %rbx      # 0xbfc0
movq (%rbx), %rdi
leaq 0x2735(%rip), %rsi      # 0x8087
leaq 0x296f(%rip), %rcx      # 0x82c8
xorl %eax, %eax
movl $0x1eb, %edx            # imm = 0x1EB
callq 0x33c0
movq (%rbx), %rcx
leaq 0x2c41(%rip), %rdi      # 0x85b0
pushq $0x1a
popq %rsi
pushq $0x1
popq %rdx
callq 0x3520
pushq $-0x1
popq %rdi
callq 0x3340