// File: /workspace/github_cpp_makefile_star2_O1/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, %ebp
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x27f0(%rip), %rsi      # 0x80ff
movq %rbx, %rdi
callq 0x32f0
testq %rax, %rax
je 0x5c92
movq %rax, %r15
leaq 0x2b7b(%rip), %rdi      # 0x84a5
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rsi
movq %rcx, %rdx
callq 0x3130
testq %rax, %rax
je 0x5c9a
movq %rax, %rbx
movq %rax, %rdi
callq 0x34a0
testq %rax, %rax
je 0x5c9f
movq %rax, %r13
movq 0x6628(%rip), %rsi      # 0xbf88
movl $0xc8, %edx
movq %rbx, %rdi
callq 0x3290
movq %rax, %rdi
callq 0x3390
testl %eax, %eax
jne 0x5ca4
movq %rbx, %rdi
movq %r15, 0x40(%rsp)
movq %r15, %rsi
callq 0x34e0
movq 0x65f4(%rip), %rsi      # 0xbf88
movl $0xc8, %edx
movq %rbx, %rdi
callq 0x3290
movq %rax, %rdi
callq 0x3390
testl %eax, %eax
jne 0x5ca9
xorl %eax, %eax
cmpl $0x1, 0x18(%r14)
setne %cl
movl %ebp, 0x8(%rsp)
movzbl %bpl, %r8d
movb %cl, %al
addl %eax, %eax
xorl %r10d, %r10d
cmpl $0x8, %r8d
movl (%r14), %r15d
movl 0x4(%r14), %r12d
movl %eax, %r9d
cmovbl %r10d, %r9d
subq $0x8, %rsp
movl %r10d, %eax
movq %rbx, %rdi
movq %r13, %rsi
movl %r15d, %edx
movl %r12d, %ecx
pushq %rax
pushq %rax
pushq %rax
callq 0x3450
addq $0x20, %rsp
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3190
movq %rbx, %rdi
movq %r13, %rsi
callq 0x30b0
movq %rax, %rbp
movq %rbx, 0x30(%rsp)
movslq 0x4(%r14), %rbx
movslq %eax, %rdi
imulq %rbx, %rdi
callq 0x3030
movq %rax, 0x28(%rsp)
movq %rbx, %rsi
movq 0x30(%rsp), %rbx
shlq $0x3, %rsi
movq %rbx, %rdi
callq 0x3460
movq %rax, %r13
movslq 0x4(%r14), %rax
testq %rax, %rax
jle 0x5a70
movslq %ebp, %rcx
xorl %edx, %edx
movl %edx, %esi
movq 0x28(%rsp), %rdx
movq %rdx, (%r13,%rsi,8)
movq %rsi, %rdi
incq %rdi
addq %rcx, %rdx
movq %rdi, %rsi
cmpq %rdi, %rax
jne 0x5a5a
movq 0x6511(%rip), %rsi      # 0xbf88
movl $0xc8, %edx
movq %rbx, %rdi
callq 0x3290
movq %rax, %rdi
callq 0x3390
testl %eax, %eax
jne 0x5cae
movl %r12d, %r9d
movslq %r15d, %rsi
movl 0x18(%r14), %eax
movl %eax, %r15d
movl 0x8(%rsp), %eax
movl %eax, 0x8(%r14)
cmpl $0x10, %eax
movq %r9, 0x20(%rsp)
je 0x5b58
cmpl $0x8, %eax
jne 0x5c2b
movq %rsi, 0x18(%rsp)
movq %r15, %rax
testl %eax, %eax
jle 0x5b48
movq 0x18(%rsp), %rax
leaq (,%rax,4), %rbx
xorl %ebp, %ebp
movl %ebp, %r12d
movl %r9d, 0xc(%rsp)
movl %r12d, %esi
movq %r14, %rdi
callq 0x5cc2
movq 0x20(%rsp), %r9
cmpl $0x0, 0xc(%rsp)
jle 0x5b3a
movl %ebp, %ecx
cmpl $0x0, (%r14)
jle 0x5b29
movl %ebp, %esi
movq %r12, %rdx
cvttss2si (%rax,%rsi,4), %edi
movq (%r13,%rcx,8), %r8
movb %dil, (%r8,%rdx)
movq %rsi, %rdi
incq %rdi
movslq (%r14), %r8
addq %r15, %rdx
movq %rdi, %rsi
cmpq %r8, %rdi
jl 0x5b07
movq %rcx, %rdx
incq %rdx
addq %rbx, %rax
movq %rdx, %rcx
cmpq %r9, %rdx
jne 0x5afc
movq %r12, %rax
incq %rax
movq %rax, %r12
cmpq %r15, %rax
jne 0x5ae3
cmpl $0x10, 0x8(%rsp)
movq 0x18(%rsp), %rsi
jne 0x5c2b
cmpl $0x8, 0x8(%r14)
movl $0x100, %edx            # imm = 0x100
movl $0x1, %eax
cmovel %edx, %eax
testl %r15d, %r15d
jle 0x5c2b
cvtsi2ss %eax, %xmm1
movq %r9, %rax
movq %rsi, %r10
shlq $0x2, %r10
leaq (%r15,%r15), %rbp
xorl %ecx, %ecx
movl %ecx, %r12d
movl %eax, 0x10(%rsp)
movq %r12, %rax
movss %xmm1, 0x14(%rsp)
movq %rax, 0x38(%rsp)
movl %eax, %esi
movq %r14, %rdi
movq %r10, %rbx
callq 0x5cc2
xorl %r11d, %r11d
movq %rbx, %r10
movss 0x14(%rsp), %xmm1
movq 0x20(%rsp), %r9
cmpl $0x0, 0x10(%rsp)
jle 0x5c13
movl %r11d, %ecx
cmpl $0x0, (%r14)
jle 0x5c02
movl %r11d, %esi
movq %r12, %rdx
movss (%rax,%rsi,4), %xmm0
mulss %xmm1, %xmm0
cvttss2si %xmm0, %ebx
movq (%r13,%rcx,8), %rdi
movb %bh, (%rdi,%rdx)
movq (%r13,%rcx,8), %rdi
movb %bl, 0x1(%rdi,%rdx)
movq %rsi, %rdi
incq %rdi
movslq (%r14), %r8
addq %rbp, %rdx
movq %rdi, %rsi
cmpq %r8, %rdi
jl 0x5bd0
movq %rcx, %rdx
incq %rdx
addq %r10, %rax
movq %rdx, %rcx
cmpq %r9, %rdx
jne 0x5bc4
movq 0x38(%rsp), %rcx
incq %rcx
addq $0x2, %r12
movq %rcx, %rax
cmpq %r15, %rcx
jne 0x5b97
movq 0x30(%rsp), %rbx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3050
movq 0x6346(%rip), %rsi      # 0xbf88
movl $0xc8, %edx
movq %rbx, %rdi
callq 0x3290
movq %rax, %rdi
callq 0x3390
testl %eax, %eax
jne 0x5cb3
xorl %eax, %eax
movl %eax, %esi
movq %rbx, %rdi
callq 0x3270
movq 0x40(%rsp), %rdi
callq 0x3240
movq %r13, %rdi
callq 0x3300
movq 0x28(%rsp), %rdi
callq 0x3350
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, %rdi
callq 0x3b89
callq 0x3b47
callq 0x3b05
callq 0x39fd
callq 0x3a3f
callq 0x3a81
callq 0x3ac3