1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17///////////////////////////////////////////////////
18// ImageUtils.cpp
19// $Id: ImageUtils.cpp,v 1.12 2011/06/17 13:35:48 mbansal Exp $
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <sys/time.h>
25
26#include "ImageUtils.h"
27
28void ImageUtils::rgba2yvu(ImageType out, ImageType in, int width, int height)
29{
30  int r,g,b, a;
31  ImageType yimg = out;
32  ImageType vimg = yimg + width*height;
33  ImageType uimg = vimg + width*height;
34  ImageType image = in;
35
36  for (int ii = 0; ii < height; ii++) {
37    for (int ij = 0; ij < width; ij++) {
38      r = (*image++);
39      g = (*image++);
40      b = (*image++);
41      a = (*image++);
42
43      if (r < 0) r = 0;
44      if (r > 255) r = 255;
45      if (g < 0) g = 0;
46      if (g > 255) g = 255;
47      if (b < 0) b = 0;
48      if (b > 255) b = 255;
49
50      int val = (int) (REDY * r + GREENY * g + BLUEY * b) / 1000 + 16;
51      if (val < 0) val = 0;
52      if (val > 255) val = 255;
53      *(yimg) = val;
54
55      val = (int) (REDV * r - GREENV * g - BLUEV * b) / 1000 + 128;
56      if (val < 0) val = 0;
57      if (val > 255) val = 255;
58      *(vimg) = val;
59
60      val = (int) (-REDU * r - GREENU * g + BLUEU * b) / 1000 + 128;
61      if (val < 0) val = 0;
62      if (val > 255) val = 255;
63      *(uimg) = val;
64
65      yimg++;
66      uimg++;
67      vimg++;
68    }
69  }
70}
71
72
73void ImageUtils::rgb2yvu(ImageType out, ImageType in, int width, int height)
74{
75  int r,g,b;
76  ImageType yimg = out;
77  ImageType vimg = yimg + width*height;
78  ImageType uimg = vimg + width*height;
79  ImageType image = in;
80
81  for (int ii = 0; ii < height; ii++) {
82    for (int ij = 0; ij < width; ij++) {
83      r = (*image++);
84      g = (*image++);
85      b = (*image++);
86
87      if (r < 0) r = 0;
88      if (r > 255) r = 255;
89      if (g < 0) g = 0;
90      if (g > 255) g = 255;
91      if (b < 0) b = 0;
92      if (b > 255) b = 255;
93
94      int val = (int) (REDY * r + GREENY * g + BLUEY * b) / 1000 + 16;
95      if (val < 0) val = 0;
96      if (val > 255) val = 255;
97      *(yimg) = val;
98
99      val = (int) (REDV * r - GREENV * g - BLUEV * b) / 1000 + 128;
100      if (val < 0) val = 0;
101      if (val > 255) val = 255;
102      *(vimg) = val;
103
104      val = (int) (-REDU * r - GREENU * g + BLUEU * b) / 1000 + 128;
105      if (val < 0) val = 0;
106      if (val > 255) val = 255;
107      *(uimg) = val;
108
109      yimg++;
110      uimg++;
111      vimg++;
112    }
113  }
114}
115
116ImageType ImageUtils::rgb2gray(ImageType in, int width, int height)
117{
118  int r,g,b, nr, ng, nb, val;
119  ImageType gray = NULL;
120  ImageType image = in;
121  ImageType out = ImageUtils::allocateImage(width, height, 1);
122  ImageType outCopy = out;
123
124  for (int ii = 0; ii < height; ii++) {
125    for (int ij = 0; ij < width; ij++) {
126      r = (*image++);
127      g = (*image++);
128      b = (*image++);
129
130      if (r < 0) r = 0;
131      if (r > 255) r = 255;
132      if (g < 0) g = 0;
133      if (g > 255) g = 255;
134      if (b < 0) b = 0;
135      if (b > 255) b = 255;
136
137      (*outCopy) = ( 0.3*r + 0.59*g + 0.11*b);
138
139      outCopy++;
140    }
141  }
142
143  return out;
144}
145
146ImageType ImageUtils::rgb2gray(ImageType out, ImageType in, int width, int height)
147{
148  int r,g,b, nr, ng, nb, val;
149  ImageType gray = out;
150  ImageType image = in;
151  ImageType outCopy = out;
152
153  for (int ii = 0; ii < height; ii++) {
154    for (int ij = 0; ij < width; ij++) {
155      r = (*image++);
156      g = (*image++);
157      b = (*image++);
158
159      if (r < 0) r = 0;
160      if (r > 255) r = 255;
161      if (g < 0) g = 0;
162      if (g > 255) g = 255;
163      if (b < 0) b = 0;
164      if (b > 255) b = 255;
165
166      (*outCopy) = ( 0.3*r + 0.59*g + 0.11*b);
167
168      outCopy++;
169    }
170  }
171
172  return out;
173
174}
175
176ImageType *ImageUtils::imageTypeToRowPointers(ImageType in, int width, int height)
177{
178  int i;
179  int m_h = height;
180  int m_w = width;
181
182  ImageType *m_rows = new ImageType[m_h];
183
184  for (i=0;i<m_h;i++) {
185    m_rows[i] = &in[(m_w)*i];
186  }
187  return m_rows;
188}
189
190void ImageUtils::yvu2rgb(ImageType out, ImageType in, int width, int height)
191{
192  int y,v,u, r, g, b;
193  unsigned char *yimg = in;
194  unsigned char *vimg = yimg + width*height;
195  unsigned char *uimg = vimg + width*height;
196  unsigned char *image = out;
197
198  for (int i = 0; i < height; i++) {
199    for (int j = 0; j < width; j++) {
200
201      y = (*yimg);
202      v = (*vimg);
203      u = (*uimg);
204
205      if (y < 0) y = 0;
206      if (y > 255) y = 255;
207      if (u < 0) u = 0;
208      if (u > 255) u = 255;
209      if (v < 0) v = 0;
210      if (v > 255) v = 255;
211
212      b = (int) ( 1.164*(y - 16) + 2.018*(u-128));
213      g = (int) ( 1.164*(y - 16) - 0.813*(v-128) - 0.391*(u-128));
214      r = (int) ( 1.164*(y - 16) + 1.596*(v-128));
215
216      if (r < 0) r = 0;
217      if (r > 255) r = 255;
218      if (g < 0) g = 0;
219      if (g > 255) g = 255;
220      if (b < 0) b = 0;
221      if (b > 255) b = 255;
222
223      *(image++) = r;
224      *(image++) = g;
225      *(image++) = b;
226
227      yimg++;
228      uimg++;
229      vimg++;
230
231    }
232  }
233}
234
235void ImageUtils::yvu2bgr(ImageType out, ImageType in, int width, int height)
236{
237  int y,v,u, r, g, b;
238  unsigned char *yimg = in;
239  unsigned char *vimg = yimg + width*height;
240  unsigned char *uimg = vimg + width*height;
241  unsigned char *image = out;
242
243  for (int i = 0; i < height; i++) {
244    for (int j = 0; j < width; j++) {
245
246      y = (*yimg);
247      v = (*vimg);
248      u = (*uimg);
249
250      if (y < 0) y = 0;
251      if (y > 255) y = 255;
252      if (u < 0) u = 0;
253      if (u > 255) u = 255;
254      if (v < 0) v = 0;
255      if (v > 255) v = 255;
256
257      b = (int) ( 1.164*(y - 16) + 2.018*(u-128));
258      g = (int) ( 1.164*(y - 16) - 0.813*(v-128) - 0.391*(u-128));
259      r = (int) ( 1.164*(y - 16) + 1.596*(v-128));
260
261      if (r < 0) r = 0;
262      if (r > 255) r = 255;
263      if (g < 0) g = 0;
264      if (g > 255) g = 255;
265      if (b < 0) b = 0;
266      if (b > 255) b = 255;
267
268      *(image++) = b;
269      *(image++) = g;
270      *(image++) = r;
271
272      yimg++;
273      uimg++;
274      vimg++;
275
276    }
277  }
278}
279
280
281ImageType ImageUtils::readBinaryPPM(const char *filename, int &width, int &height)
282{
283
284  FILE *imgin = NULL;
285  int mval=0, format=0, eret;
286  ImageType ret = IMAGE_TYPE_NOIMAGE;
287
288  imgin = fopen(filename, "r");
289  if (imgin == NULL) {
290    fprintf(stderr, "Error: Filename %s not found\n", filename);
291    return ret;
292  }
293
294  eret = fscanf(imgin, "P%d\n", &format);
295  if (format != 6) {
296    fprintf(stderr, "Error: readBinaryPPM only supports PPM format (P6)\n");
297    return ret;
298  }
299
300  eret = fscanf(imgin, "%d %d\n", &width, &height);
301  eret = fscanf(imgin, "%d\n", &mval);
302  ret  = allocateImage(width, height, IMAGE_TYPE_NUM_CHANNELS);
303  eret = fread(ret, sizeof(ImageTypeBase), IMAGE_TYPE_NUM_CHANNELS*width*height, imgin);
304
305  fclose(imgin);
306
307  return ret;
308
309}
310
311void ImageUtils::writeBinaryPPM(ImageType image, const char *filename, int width, int height, int numChannels)
312{
313  FILE *imgout = fopen(filename, "w");
314
315  if (imgout == NULL) {
316    fprintf(stderr, "Error: Filename %s could not be opened for writing\n", filename);
317    return;
318  }
319
320  if (numChannels == 3) {
321    fprintf(imgout, "P6\n%d %d\n255\n", width, height);
322  } else if (numChannels == 1) {
323    fprintf(imgout, "P5\n%d %d\n255\n", width, height);
324  } else {
325    fprintf(stderr, "Error: writeBinaryPPM: Unsupported number of channels\n");
326  }
327  fwrite(image, sizeof(ImageTypeBase), numChannels*width*height, imgout);
328
329  fclose(imgout);
330
331}
332
333ImageType ImageUtils::allocateImage(int width, int height, int numChannels, short int border)
334{
335  int overallocation = 256;
336 return (ImageType) calloc(width*height*numChannels+overallocation, sizeof(ImageTypeBase));
337}
338
339
340void ImageUtils::freeImage(ImageType image)
341{
342  free(image);
343}
344
345
346// allocation of one color image used for tmp buffers, etc.
347// format of contiguous memory block:
348//    YUVInfo struct (type + BimageInfo for Y,U, and V),
349//    Y row pointers
350//    U row pointers
351//    V row pointers
352//    Y image pixels
353//    U image pixels
354//    V image pixels
355YUVinfo *YUVinfo::allocateImage(unsigned short width, unsigned short height)
356{
357    unsigned short heightUV, widthUV;
358
359    widthUV = width;
360    heightUV = height;
361
362    // figure out how much space to hold all pixels...
363    int size = ((width * height * 3) + 8);
364    unsigned char *position = 0;
365
366    // VC 8 does not like calling free on yuv->Y.ptr since it is in
367    // the middle of a block.  So rearrange the memory layout so after
368    // calling mapYUVInforToImage yuv->Y.ptr points to the begginning
369    // of the calloc'ed block.
370    YUVinfo *yuv = (YUVinfo *) calloc(sizeof(YUVinfo), 1);
371    if (yuv) {
372        yuv->Y.width  = yuv->Y.pitch = width;
373        yuv->Y.height = height;
374        yuv->Y.border = yuv->U.border = yuv->V.border = (unsigned short) 0;
375        yuv->U.width  = yuv->U.pitch = yuv->V.width = yuv->V.pitch = widthUV;
376        yuv->U.height = yuv->V.height = heightUV;
377
378        unsigned char* block = (unsigned char*) calloc(
379                sizeof(unsigned char *) * (height + heightUV + heightUV) +
380                sizeof(unsigned char) * size, 1);
381
382        position = block;
383        unsigned char **y = (unsigned char **) (block + size);
384
385        /* Initialize and assign row pointers */
386        yuv->Y.ptr = y;
387        yuv->V.ptr = &y[height];
388        yuv->U.ptr = &y[height + heightUV];
389    }
390    if (size)
391        mapYUVInfoToImage(yuv, position);
392    return yuv;
393}
394
395// wrap YUVInfo row pointers around 3 contiguous image (color component) planes.
396// position = starting pixel in image.
397void YUVinfo::mapYUVInfoToImage(YUVinfo *img, unsigned char *position)
398{
399    int i;
400    for (i = 0; i < img->Y.height; i++, position += img->Y.width)
401        img->Y.ptr[i] = position;
402    for (i = 0; i < img->V.height; i++, position += img->V.width)
403        img->V.ptr[i] = position;
404    for (i = 0; i < img->U.height; i++, position += img->U.width)
405        img->U.ptr[i] = position;
406}
407
408
409