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 *pSurface = NULL; 53 54 snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); 55 resPath[sizeof(resPath)-1] = '\0'; 56 FILE* fp = fopen(resPath, "rb"); 57 if (fp == NULL) { 58 result = -1; 59 goto exit; 60 } 61 62 size_t bytesRead = fread(header, 1, sizeof(header), fp); 63 if (bytesRead != sizeof(header)) { 64 result = -2; 65 goto exit; 66 } 67 68 if (png_sig_cmp(header, 0, sizeof(header))) { 69 result = -3; 70 goto exit; 71 } 72 73 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 74 if (!png_ptr) { 75 result = -4; 76 goto exit; 77 } 78 79 info_ptr = png_create_info_struct(png_ptr); 80 if (!info_ptr) { 81 result = -5; 82 goto exit; 83 } 84 85 if (setjmp(png_jmpbuf(png_ptr))) { 86 result = -6; 87 goto exit; 88 } 89 90 png_init_io(png_ptr, fp); 91 png_set_sig_bytes(png_ptr, sizeof(header)); 92 png_read_info(png_ptr, info_ptr); 93 94 size_t width = info_ptr->width; 95 size_t height = info_ptr->height; 96 size_t stride = 4 * width; 97 size_t pixelSize = stride * height; 98 99 int color_type = info_ptr->color_type; 100 int bit_depth = info_ptr->bit_depth; 101 int channels = info_ptr->channels; 102 if (!(bit_depth == 8 && 103 ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || 104 (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) || 105 (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) { 106 return -7; 107 goto exit; 108 } 109 110 surface = malloc(sizeof(GGLSurface) + pixelSize); 111 if (surface == NULL) { 112 result = -8; 113 goto exit; 114 } 115 unsigned char* pData = (unsigned char*) (surface + 1); 116 surface->version = sizeof(GGLSurface); 117 surface->width = width; 118 surface->height = height; 119 surface->stride = width; /* Yes, pixels, not bytes */ 120 surface->data = pData; 121 surface->format = (channels == 3) ? 122 GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888; 123 124 int alpha = 0; 125 if (color_type == PNG_COLOR_TYPE_PALETTE) { 126 png_set_palette_to_rgb(png_ptr); 127 } 128 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 129 png_set_tRNS_to_alpha(png_ptr); 130 alpha = 1; 131 } 132 133 int y; 134 if (channels == 3 || (channels == 1 && !alpha)) { 135 for (y = 0; y < height; ++y) { 136 unsigned char* pRow = pData + y * stride; 137 png_read_row(png_ptr, pRow, NULL); 138 139 int x; 140 for(x = width - 1; x >= 0; x--) { 141 int sx = x * 3; 142 int dx = x * 4; 143 unsigned char r = pRow[sx]; 144 unsigned char g = pRow[sx + 1]; 145 unsigned char b = pRow[sx + 2]; 146 unsigned char a = 0xff; 147 pRow[dx ] = r; // r 148 pRow[dx + 1] = g; // g 149 pRow[dx + 2] = b; // b 150 pRow[dx + 3] = a; 151 } 152 } 153 } else { 154 for (y = 0; y < height; ++y) { 155 unsigned char* pRow = pData + y * stride; 156 png_read_row(png_ptr, pRow, NULL); 157 } 158 } 159 160 *pSurface = (gr_surface) surface; 161 162 exit: 163 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 164 165 if (fp != NULL) { 166 fclose(fp); 167 } 168 if (result < 0) { 169 if (surface) { 170 free(surface); 171 } 172 } 173 return result; 174 } 175 176 void res_free_surface(gr_surface surface) { 177 GGLSurface* pSurface = (GGLSurface*) surface; 178 if (pSurface) { 179 free(pSurface); 180 } 181 } 182