Add facility to read frames in RGB & RGBA format
[imageviewer.git] / rawIOppm.cpp
blob75f21372a18821fa88b1dbb1a52004e0d459cdbf
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id$
5 * The MIT License
7 * Copyright (c) 2008 BBC Research
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
27 * ***** END LICENSE BLOCK ***** */
29 #include <assert.h>
30 #include <math.h>
32 #include "rawIOppm.h"
34 /* convert one line of 422 chroma to 444 */
35 void RawWriterppm::chroma422to444(const Array2d<int>& in, const int line,
36 Array1d<int>& out) const
38 Array1d<int> ChromaLine((in.width()*2) + 2);
39 ChromaLine.assign(0);
41 /* generate zero stuffed chroma */
42 for (int x=0; x<in.width()*2; x+=2) {
43 ChromaLine[x+1] = in[line][x/2]; //offset ChromaLine by 1 to get pixel at x=-1
46 /* filter */
47 for (int x=0; x<in.width()*2; x++) {
49 /* 1/2, 1/2 filter *///note the odd indexing to the array
50 int C = ChromaLine[x]; //tap at 'x-1'
51 C += ChromaLine[x+1] * 2; //tap at 'x'
52 C += ChromaLine[x+2]; //tap at 'x+1'
54 /* round and shift */
55 C++;
56 C >>= 1;
58 out[x] = C;
62 /* convert a line of YUV to RGB */
63 void RawWriterppm::yuv2rgb(const Array2d<int>& Y, const int lineNum,
64 const Array1d<int>& ULine, const Array1d<int>& VLine,
65 Array1d<int>& RLine, Array1d<int>& GLine,
66 Array1d<int>& BLine, int depth) const
68 int maxVal = (1 << depth) - 1;
69 //int yOffset = 1 << (depth - 4);
71 for (int x=0; x<ULine.length(); x++) {
73 //int L = Y[lineNum][x] - yOffset;
74 int L = Y[lineNum][x];
75 int U = ULine[x];
76 int V = VLine[x];
78 //Matrix YUV to RGB - Tims, scales output 0-255
79 //int R = ((298*L + 409*V + 128)>>8);
80 //int G = ((298*L - 100*U - 208*V + 128)>>8);
81 //int B = ((298*L + 516*U + 128)>>8);
83 // Jons - leaves output at same range as input
84 int R = ((256*L + 394*V + 128)>>8);
85 int G = ((256*L - 46*U - 117*V + 128)>>8);
86 int B = ((256*L + 464*U + 128)>>8);
88 //printf("Y=%d U=%d V=%d R=%d G=%d B=%d\n", L, U, V, R, G, B);
90 //Clip
91 RLine[x] = (R < 0) ? 0 : ((R > maxVal) ? maxVal : R);
92 GLine[x] = (G < 0) ? 0 : ((G > maxVal) ? maxVal : G);
93 BLine[x] = (B < 0) ? 0 : ((B > maxVal) ? maxVal : B);
95 //printf("Clipped Y=%d U=%d V=%d R=%d G=%d B=%d\n", L, U, V, RLine[x], GLine[x], BLine[x]);
99 void RawWriterppm::writeCr422(const RawFrame& f) const
101 int maxVal = (1 << depth) - 1;
103 fprintf(outfile, "P6 %d %d %d\n", f.luma.width(), f.luma.height(), maxVal);
105 int mask = (1 << (depth - 8)) - 1;
107 for (int y=0; y < f.luma.height(); y++) {
109 Array1d<int> ULine(f.luma.width());
110 Array1d<int> VLine(f.luma.width());
112 Array1d<int> RLine(f.luma.width());
113 Array1d<int> GLine(f.luma.width());
114 Array1d<int> BLine(f.luma.width());
116 /* upconvert a line of chroma */
117 chroma422to444(f.cb, y, ULine);
118 chroma422to444(f.cr, y, VLine);
120 /* convert to RGB */
121 yuv2rgb(f.luma, y, ULine, VLine, RLine, GLine, BLine, depth);
123 for (int x=0; x<f.luma.width(); x++) {
125 if (depth > 8) {
128 fputc((RLine[x] >> 8) & mask, outfile);
129 fputc((RLine[x] & 0xff), outfile);
131 fputc((GLine[x] >> 8) & mask, outfile);
132 fputc((GLine[x] & 0xff), outfile);
134 fputc((BLine[x] >> 8) & mask, outfile);
135 fputc((BLine[x] & 0xff), outfile);
137 else {
138 fputc((RLine[x] & 0xff), outfile);
139 fputc((GLine[x] & 0xff), outfile);
140 fputc((BLine[x] & 0xff), outfile);
146 void RawWriterppm::writeYOnly(const RawFrame& f) const
148 /* YYYY (Planar)
150 assert(f.chroma == RawFrame::YOnly);
152 fprintf(outfile, "P6 %d %d %d\n", f.luma.width(), f.luma.height(), (1
153 << depth) - 1);
155 if (depth > 8) {
156 int mask = (1 << (depth - 8)) - 1;
157 for (int y = 0; y < f.luma.height(); y++)
158 for (int x = 0; x < f.luma.width(); x++) {
161 fputc((f.luma[y][x] >> 8) & mask, outfile);
162 fputc((f.luma[y][x] & 0xff), outfile);
164 fputc((f.luma[y][x] >> 8) & mask, outfile);
165 fputc((f.luma[y][x] & 0xff), outfile);
167 fputc((f.luma[y][x] >> 8) & mask, outfile);
168 fputc((f.luma[y][x] & 0xff), outfile);
171 else {
172 for (int y = 0; y < f.luma.height(); y++)
173 for (int x = 0; x < f.luma.width(); x++) {
176 fputc((f.luma[y][x] & 0xff), outfile);
178 fputc((f.luma[y][x] & 0xff), outfile);
180 fputc((f.luma[y][x] & 0xff), outfile);
185 void RawReaderppm::readHeader()
187 // This works for our files, but is not generalised:
188 fscanf(infile, "P6 %d %d %d\n", &_width, &_height, &_maxval);
190 _depth = (int)ceil(log((double)_maxval) / log(2.0));
194 RawFrame& RawReaderppm::read(RawFrame &f)
196 assert(f.chroma == RawFrame::CrRGB);
198 size_t linesRead;
199 size_t lineLen;
201 if (_maxval > 255) {
202 lineLen = f.luma.width() * 3 * 2;
203 unsigned char *inLine = new unsigned char[lineLen];
205 for (int y = 0; y < _height; y++) {
207 linesRead = fread(inLine, lineLen, 1, infile);
209 for (int in=0, x=0; x < _width; x++, in+=6) {
210 f.r[y][x]=inLine[in+0]*256 + inLine[in+1];
211 f.g[y][x]=inLine[in+2]*256 + inLine[in+3];
212 f.b[y][x]=inLine[in+4]*256 + inLine[in+5];
215 if (linesRead < 1)
216 goto exit1;
218 exit1: free(inLine);
220 else {
221 lineLen = f.luma.width() * 3;
222 unsigned char *inLine = new unsigned char[lineLen];
224 for (int y = 0; y < _height; y++) {
226 linesRead = fread(inLine, lineLen, 1, infile);
228 for (int in=0, x=0; x < _width; x++, in+=3) {
229 f.r[y][x]=inLine[in];
230 f.g[y][x]=inLine[in+1];
231 f.b[y][x]=inLine[in+2];
234 if (linesRead < 1)
235 goto exit2;
237 exit2: free(inLine);
240 return f;
243 RawFrame& RawReaderppm::read()
245 throw;