File: png.cpp

package info (click to toggle)
embree 3.12.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 27,412 kB
  • sloc: cpp: 173,822; xml: 3,737; ansic: 2,955; python: 1,628; sh: 480; makefile: 193; csh: 42
file content (135 lines) | stat: -rw-r--r-- 4,107 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2009-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#ifdef EMBREE_TUTORIALS_LIBPNG

#include "image.h"

#include <iostream>
#include <cstring>
#include <cstdio>
#include <png.h>

namespace embree
{
  struct AutoCloseFile
  {
    FILE* file;
    AutoCloseFile (FILE* file) : file(file) {}
    ~AutoCloseFile () { if (file) fclose(file); }
  };

  /*! read PNG file from disk */
  Ref<Image> loadPNG(const FileName& fileName)
  {
    size_t width, height;

    //header for testing if it is a png
    png_byte header[8];
 
    //open file as binary
    FILE* fp = fopen(fileName.c_str(), "rb");
    if (!fp) THROW_RUNTIME_ERROR("cannot open file "+fileName.str());
    //ON_SCOPE_EXIT(fclose(fp));
    AutoCloseFile close_file(fp);

    //read the header
    if (fread(header, 1, 8, fp) != 8)
      THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str());

    //test if png
    int is_png = !png_sig_cmp(header, 0, 8);
    if (!is_png)
      THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str());

    //create png struct
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png_ptr) THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str());
    ON_SCOPE_EXIT(png_destroy_read_struct(&png_ptr, (png_infopp) nullptr, (png_infopp) nullptr));
    
    //create png info struct
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
      THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str());
 
    //create png info struct
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) 
      THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str());
 
    //png error stuff, not sure libpng man suggests this.
    //if (setjmp(png_jmpbuf(png_ptr))) {
    ///  return (TEXTURE_LOAD_ERROR);
    //}
 
    //init png reading
    png_init_io(png_ptr, fp);
 
    //let libpng know you already read the first 8 bytes
    png_set_sig_bytes(png_ptr, 8);
 
    // read all the info up to the image data
    png_read_info(png_ptr, info_ptr);
 
    //variables to pass to get info
    int bit_depth, color_type;
    png_uint_32 twidth, theight;
 
    // get info about png
    png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
                 nullptr, nullptr, nullptr);
 
    //update width and height based on png info
    width = twidth;
    height = theight;
    
    Ref<Image> img = new Image4uc(width,height,fileName);

    // Update the png info struct.
    png_read_update_info(png_ptr, info_ptr);
 
    // Row size in bytes.
    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    // Allocate the image_data as a big block, to be given to opengl
    std::vector<png_byte> data(rowbytes * height);
 
    // row_pointers is for pointing to image_data for reading the png with libpng
    std::vector<png_bytep> row_pointers(height);

    // set the individual row_pointers to point at the correct offsets of image_data
    for (size_t i = 0; i < height; ++i)
      row_pointers[i] = (unsigned char*) &data[i * rowbytes];
 
    // read the png into image_data through row_pointers
    png_read_image(png_ptr, row_pointers.data());
  
    if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8)
    {
      for (size_t y=0;y<height;y++)
        for (size_t x=0;x<width;x++)
        {
          unsigned char* texel = data.data() + (y * width + x) * 3;
          Color4 c( (float)texel[0] * 1.0f/255.0f, (float)texel[1] * 1.0f/255.0f, (float)texel[2] * 1.0f/255.0f, 0.0f );
          img.ptr->set(x,y,c);
        }
    }
    else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8)
    {
      for (size_t y=0;y<height;y++)
        for (size_t x=0;x<width;x++)
        {
          unsigned char *texel = data.data() + (y * width + x) * 4;
          Color4 c( (float)texel[0] * 1.0f/255.0f, (float)texel[1] * 1.0f/255.0f, (float)texel[2] * 1.0f/255.0f, (float)texel[3] * 1.0f/255.0f );
          img.ptr->set(x,y,c);
        }
    }
    else
      THROW_RUNTIME_ERROR("invalid color type in PNG file "+fileName.str());
      
    return img;
  }
}

#endif