1 /* 2 * Copyright (C) 2007 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 #include <stdlib.h> 18 #include <unistd.h> 19 20 #include <fcntl.h> 21 #include <stdio.h> 22 23 #include <sys/ioctl.h> 24 #include <sys/mman.h> 25 #include <sys/types.h> 26 27 #include <linux/fb.h> 28 #include <linux/kd.h> 29 30 #include <pixelflinger/pixelflinger.h> 31 32 #include <png.h> 33 34 #include "minui.h" 35 36 // libpng gives "undefined reference to 'pow'" errors, and I have no 37 // idea how to convince the build system to link with -lm. We don't 38 // need this functionality (it's used for gamma adjustment) so provide 39 // a dummy implementation to satisfy the linker. 40 double pow(double x, double y) { 41 return x; 42 } 43 44 int res_create_surface(const char* name, gr_surface* pSurface) { 45 char resPath[256]; 46 GGLSurface* surface = NULL; 47 int result = 0; 48 unsigned char header[8]; 49 png_structp png_ptr = NULL; 50 png_infop info_ptr = NULL; 51 52 snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); 53 resPath[sizeof(resPath)-1] = '\0'; 54 FILE* fp = fopen(resPath, "rb"); 55 if (fp == NULL) { 56 result = -1; 57 goto exit; 58 } 59 60 size_t bytesRead = fread(header, 1, sizeof(header), fp); 61 if (bytesRead != sizeof(header)) { 62 result = -2; 63 goto exit; 64 } 65 66 if (png_sig_cmp(header, 0, sizeof(header))) { 67 result = -3; 68 goto exit; 69 } 70 71 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 72 if (!png_ptr) { 73 result = -4; 74 goto exit; 75 } 76 77 info_ptr = png_create_info_struct(png_ptr); 78 if (!info_ptr) { 79 result = -5; 80 goto exit; 81 } 82 83 if (setjmp(png_jmpbuf(png_ptr))) { 84 result = -6; 85 goto exit; 86 } 87 88 png_init_io(png_ptr, fp); 89 png_set_sig_bytes(png_ptr, sizeof(header)); 90 png_read_info(png_ptr, info_ptr); 91 92 size_t width = info_ptr->width; 93 size_t height = info_ptr->height; 94 size_t stride = 4 * width; 95 size_t pixelSize = stride * height; 96 97 int color_type = info_ptr->color_type; 98 int bit_depth = info_ptr->bit_depth; 99 int channels = info_ptr->channels; 100 if (!(bit_depth == 8 && 101 ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || 102 (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || 103 (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) { 104 return -7; 105 goto exit; 106 } 107 108 surface = malloc(sizeof(GGLSurface) + pixelSize); 109 if (surface == NULL) { 110 result = -8; 111 goto exit; 112 } 113 unsigned char* pData = (unsigned char*) (surface + 1); 114 surface->version = sizeof(GGLSurface); 115 surface->width = width; 116 surface->height = height; 117 surface->stride = width; /* Yes, pixels, not bytes */ 118 surface->data = pData; 119 surface->format = (channels == 3) ? 120 GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888; 121 122 if (color_type == PNG_COLOR_TYPE_PALETTE) { 123 png_set_palette_to_rgb(png_ptr); 124 } 125 126 int y; 127 if (channels == 3) { 128 for (y = 0; y < height; ++y) { 129 unsigned char* pRow = pData + y * stride; 130 png_read_row(png_ptr, pRow, NULL); 131 132 int x; 133 for(x = width - 1; x >= 0; x--) { 134 int sx = x * 3; 135 int dx = x * 4; 136 unsigned char r = pRow[sx]; 137 unsigned char g = pRow[sx + 1]; 138 unsigned char b = pRow[sx + 2]; 139 unsigned char a = 0xff; 140 pRow[dx ] = r; // r 141 pRow[dx + 1] = g; // g 142 pRow[dx + 2] = b; // b 143 pRow[dx + 3] = a; 144 } 145 } 146 } else { 147 for (y = 0; y < height; ++y) { 148 unsigned char* pRow = pData + y * stride; 149 png_read_row(png_ptr, pRow, NULL); 150 } 151 } 152 153 *pSurface = (gr_surface) surface; 154 155 exit: 156 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 157 158 if (fp != NULL) { 159 fclose(fp); 160 } 161 if (result < 0) { 162 if (surface) { 163 free(surface); 164 } 165 } 166 return result; 167 } 168 169 void res_free_surface(gr_surface surface) { 170 GGLSurface* pSurface = (GGLSurface*) surface; 171 if (pSurface) { 172 free(pSurface); 173 } 174 } 175