File: HDRBitmapReader.java

package info (click to toggle)
sunflow 0.07.2.svn396%2Bdfsg-14
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 11,164 kB
  • ctags: 4,980
  • sloc: lisp: 168,740; java: 25,216; cpp: 3,265; python: 2,058; ruby: 1,276; xml: 105; sh: 85; makefile: 62
file content (181 lines) | stat: -rw-r--r-- 7,403 bytes parent folder | download | duplicates (5)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package org.sunflow.image.readers;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import org.sunflow.image.Bitmap;
import org.sunflow.image.BitmapReader;
import org.sunflow.image.formats.BitmapRGBE;

public class HDRBitmapReader implements BitmapReader {
    public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
        // EP : Try to read filename as an URL or as a file
        InputStream f;
        try {
            // Let's try first to read filename as an URL
            URLConnection connection = new URL(filename).openConnection();
            if (connection instanceof JarURLConnection) {
                JarURLConnection urlConnection = (JarURLConnection) connection;
                URL jarFileUrl = urlConnection.getJarFileURL();
                if (jarFileUrl.getProtocol().equalsIgnoreCase("file")) {
                    try {
                        if (new File(jarFileUrl.toURI()).canWrite()) {
                            // Refuse to use cache to be able to delete the writable files accessed with jar protocol,
                            // as suggested in http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6962459
                            connection.setUseCaches(false);
                        }
                    } catch (URISyntaxException ex) {
                        throw new IOException(ex);
                    }
                }
            }
            f = connection.getInputStream();
        } catch (MalformedURLException ex) {
            // Let's try to read filename as a file
            f = new FileInputStream(filename);
        }

        f = new BufferedInputStream(f);
        // End of modification

        // parse header
        boolean parseWidth = false, parseHeight = false;
        int width = 0, height = 0;
        int last = 0;
        while (width == 0 || height == 0 || last != '\n') {
            int n = f.read();
            switch (n) {
                case 'Y':
                    parseHeight = last == '-';
                    parseWidth = false;
                    break;
                case 'X':
                    parseHeight = false;
                    parseWidth = last == '+';
                    break;
                case ' ':
                    parseWidth &= width == 0;
                    parseHeight &= height == 0;
                    break;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    if (parseHeight)
                        height = 10 * height + (n - '0');
                    else if (parseWidth)
                        width = 10 * width + (n - '0');
                    break;
                default:
                    parseWidth = parseHeight = false;
                    break;
            }
            last = n;
        }
        // allocate image
        int[] pixels = new int[width * height];
        if ((width < 8) || (width > 0x7fff)) {
            // run length encoding is not allowed so read flat
            readFlatRGBE(f, 0, width * height, pixels);
        } else {
            int rasterPos = 0;
            int numScanlines = height;
            int[] scanlineBuffer = new int[4 * width];
            while (numScanlines > 0) {
                int r = f.read();
                int g = f.read();
                int b = f.read();
                int e = f.read();
                if ((r != 2) || (g != 2) || ((b & 0x80) != 0)) {
                    // this file is not run length encoded
                    pixels[rasterPos] = (r << 24) | (g << 16) | (b << 8) | e;
                    readFlatRGBE(f, rasterPos + 1, width * numScanlines - 1, pixels);
                    break;
                }

                if (((b << 8) | e) != width)
                    throw new BitmapFormatException("Invalid scanline width");
                int p = 0;
                // read each of the four channels for the scanline into
                // the buffer
                for (int i = 0; i < 4; i++) {
                    if (p % width != 0)
                        throw new BitmapFormatException("Unaligned access to scanline data");
                    int end = (i + 1) * width;
                    while (p < end) {
                        int b0 = f.read();
                        int b1 = f.read();
                        if (b0 > 128) {
                            // a run of the same value
                            int count = b0 - 128;
                            if ((count == 0) || (count > (end - p)))
                                throw new BitmapFormatException("Bad scanline data - invalid RLE run");

                            while (count-- > 0) {
                                scanlineBuffer[p] = b1;
                                p++;
                            }
                        } else {
                            // a non-run
                            int count = b0;
                            if ((count == 0) || (count > (end - p)))
                                throw new BitmapFormatException("Bad scanline data - invalid count");
                            scanlineBuffer[p] = b1;
                            p++;
                            if (--count > 0) {
                                for (int x = 0; x < count; x++)
                                    scanlineBuffer[p + x] = f.read();
                                p += count;
                            }
                        }
                    }
                }
                // now convert data from buffer into floats
                for (int i = 0; i < width; i++) {
                    r = scanlineBuffer[i];
                    g = scanlineBuffer[i + width];
                    b = scanlineBuffer[i + 2 * width];
                    e = scanlineBuffer[i + 3 * width];
                    pixels[rasterPos] = (r << 24) | (g << 16) | (b << 8) | e;
                    rasterPos++;
                }
                numScanlines--;
            }
        }
        f.close();
        // flip image
        for (int y = 0, i = 0, ir = (height - 1) * width; y < height / 2; y++, ir -= width) {
            for (int x = 0, i2 = ir; x < width; x++, i++, i2++) {
                int t = pixels[i];
                pixels[i] = pixels[i2];
                pixels[i2] = t;
            }
        }
        return new BitmapRGBE(width, height, pixels);
    }

    private void readFlatRGBE(InputStream f, int rasterPos, int numPixels, int[] pixels) throws IOException {
        while (numPixels-- > 0) {
            int r = f.read();
            int g = f.read();
            int b = f.read();
            int e = f.read();
            pixels[rasterPos] = (r << 24) | (g << 16) | (b << 8) | e;
            rasterPos++;
        }
    }
}