int naMain(JNIEnv* env, jobject pObj, jstring pCmdStr, jobject pMainActObj) { char progBuf[500]; jmethodID updateProgMID, toStringMID; jstring progStr; jclass mainActivityClass = (*env)->GetObjectClass(env, pMainActObj); cachedMainActObj = (*env)->NewGlobalRef(env, pMainActObj); // toStringMID = (*env)->GetMethodID(env, mainActivityClass, "toString", "()Ljava/lang/String;"); // jstring name = (*env)->CallObjectMethod(env, pMainActObj, toStringMID); // const jbyte* nameStr = (*env)->GetStringUTFChars(env, name, NULL); // LOGI(2, "toString: %s", nameStr); // (*env)->ReleaseStringUTFChars(env, name, nameStr); updateProgMID = (*env)->GetMethodID(env, mainActivityClass, "updateProgress", "(Ljava/lang/String;I)V"); if (NULL == updateProgMID) { LOGE(1, "error finding method updateProgress"); return EXIT_FAILURE; } // char* test = "test"; // jstring jtest = (*env)->NewStringUTF(env, test); // (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, jtest); int argc = 0; char** argv = (char**) malloc (sizeof(char*)*4); //the first input argument should be the program name itself *argv = "fusch"; char** targv = argv + 1; argc++; jboolean isCopy; char *cmdstr = (*env)->GetStringUTFChars(env, pCmdStr, &isCopy); if (NULL == cmdstr) { LOGI(2, "get string failed"); return EXIT_FAILURE; } char* pch; pch = strtok(cmdstr, " "); while (NULL != pch) { *targv = pch; argc++; targv++; pch = strtok(NULL, " "); } LOGI(1, "No. of arguments: %d", argc); LOGI(1, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); #else int main(int argc, char *argv[]) { #endif setlocale(LC_ALL, ""); setvbuf(stdout, (char*)NULL, _IONBF, 0); if(argc != 4) { fprintf(stderr, MSG[I_HELP1], argv[0]); fputs(MSG[I_HELP2], stderr); return EXIT_FAILURE; } char *inname = argv[1], *outname = argv[2], *valarg = argv[3]; /* Quelldatei oeffnen und auf PNG-Signatur ueberpruefen **********************/ #ifdef ANDROID_BUILD // progStr = (*env)->NewStringUTF(env, MSG[I_OPEN]); // (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else puts(MSG[I_OPEN]); #endif FILE *f; f = fopen(inname, "rb"); if (f == NULL) { fputs(inname, stderr); fputs(MSG[E_OPEN], stderr); fputc('\n', stderr); return EXIT_FAILURE; } unsigned char sig[SIG_BYTES]; fread(sig, 1, SIG_BYTES, f); if (png_sig_cmp(sig, 0, SIG_BYTES)) { fputs(inname, stderr); fputs(MSG[E_CORRUPTED], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } /* PNG-Lesevorgang initialisieren *****************************************/ png_struct *png_ptr; png_info *info_ptr, *end_info; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); end_info = png_create_info_struct(png_ptr); try_png_read( (info_ptr == NULL) || (end_info == NULL), &png_ptr, &info_ptr, &end_info, f, (char*)NULL ); try_png_read( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, &end_info, f, MSG[E_READ] ); png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, SIG_BYTES); /* Bildinfo lesen: Bilddimensionen und ggf. Farbpalette. * Palette ggf. konvertieren. *********************************************/ long int width, height, pwidth, pheight; // png_uint_32 width, height, pwidth, pheight; comp_t *image, **row, *rwp; png_read_info(png_ptr, info_ptr); width = info_ptr->width; height = info_ptr->height; const long int original_width = info_ptr->width; const int bit_depth = info_ptr->bit_depth, color_type = info_ptr->color_type; const bool image_is_pal = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE); const bool image_is_gray = ( (color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ); const bool alpha = ( (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA) ); int num_palette = 0; png_color *png_pal_got = NULL; if (image_is_pal) try_png_read( !png_get_PLTE(png_ptr, info_ptr, &png_pal_got, &num_palette), &png_ptr, &info_ptr, &end_info, f, MSG[E_READPAL] ); png_color png_pal[num_palette]; comp_t comp_pal[num_palette]; if (image_is_pal) for (int i = 0; i < num_palette; i++) { png_pal[i] = png_pal_got[i]; comp_t c; c = png_pal[i].red; c <<= CHAR_BIT; c |= png_pal[i].green; c <<= CHAR_BIT; c |= png_pal[i].blue; comp_pal[i] = c; } png_color_16 *img_bkgd; png_color_16 background; if (png_get_bKGD(png_ptr, info_ptr, &img_bkgd)) background = *img_bkgd; /* Parameter fuer Groessenaenderung auswerten: * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ******************/ long int diff; bool vert; bool aspp = false, asp2 = false, enlg = false, sign = true; switch (tolower(*valarg++)) { case 'h': vert = false; break; case 'v': vert = true; break; case '%': aspp = true; break; case '@': asp2 = true; break; default : try_png_read(true, &png_ptr, &info_ptr, &end_info, f, MSG[E_DIM]); } switch (*valarg) { case '+': enlg = true; break; case '-': enlg = false; break; default: sign = false; break; } diff = atol(valarg); bool valargok = !!diff; if (aspp || asp2) { try_png_read(!sign, &png_ptr, &info_ptr, &end_info, f, MSG[E_SIGN]); const float fheight = (float)height, fwidth = (float)width, casp = fheight / fwidth; float nasp; if (asp2) { const char *aspsw = strtok(valarg, ":"), *aspsh = strtok((char*)NULL, ":"); valargok = ((aspsw != NULL) && (aspsh != NULL)); const float aspw = valargok? atol(aspsw): 0, asph = valargok? atol(aspsh): 0; nasp = valargok? fabs(asph / aspw): 0; } else nasp = ((float)labs(diff) / 100.0f); vert = ((nasp < casp) ^ enlg); diff = valargok? labs(vert? (height - (fwidth * nasp)): (width - (fheight / nasp)) ): 0; if (!enlg) diff = -diff; } if (!diff) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); if (valargok) { #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[I_NOTHINGTODO]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else puts(MSG[I_NOTHINGTODO]); #endif // const char copycmd[] = "copy /b /y"; const char copycmd[] = "cp"; char copycmdln[ strlen(copycmd) + strlen(argv[1]) + strlen(argv[2]) + 7 ]; sprintf( copycmdln, "%s \"%s\" \"%s\"", copycmd, argv[1], argv[2] ); return system(copycmdln); } try_png_read(!valargok, &png_ptr, &info_ptr, &end_info, f, MSG[E_PAR]); } if (!(aspp || asp2 || sign)) diff -= vert? height: width; try_png_read( labs(diff) > (vert? height: width), &png_ptr, &info_ptr, &end_info, f, MSG[E_SIZE] ); /* Bild- sowie Zeilenzeigerspeicher anfordern und Zeiger setzen. **********/ image = malloc(width * height * sizeof(comp_t)); try_png_read(image == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); row = malloc(height * sizeof(comp_t*)); try_png_read(row == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Bild laden. * Falls Alphakanal vorhanden, Alpha invertieren: hoher Wert => hohe Deckung. * Falls Nicht-Palettenbild ohne Alphakanal (24 bpp) oder Graubild * (8 oder 16 bpp), mit "png_set_filler" die Bilddaten auf 32 bzw. 16 bpp * ausweiten. 32 Bit ist die * comp_t-Breite. ****************************/ #ifdef ANDROID_BUILD // progStr = (*env)->NewStringUTF(env, MSG[I_LOAD]); // (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else puts(MSG[I_LOAD]); #endif if (alpha) png_set_invert_alpha(png_ptr); else if (!image_is_pal) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_read_image(png_ptr, (void*)row); /* Falls 8 oder 16 bpp, Bilddaten auf "Pixel = comp_t-Element" ausweiten. */ // trw: Temporaere Zeile. void *trw = malloc(image_is_gray? (width * 2): width); try_png_read(trw == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); // Zunaechst Bildzeile nach Temporaerzeile kopieren, dann Elemente einzeln zurueck. if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } /* Lesevorgang beenden und Quelldatei schliessen. ************************/ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); #ifdef ANDROID_BUILD sprintf(progBuf, "%s: %d*%d > %d*%d: %s %+d", MSG[I_MEASURES], width, height, vert? width: width + diff, vert? height + diff: height, vert? MSG[I_VERT]: MSG[I_HORI], diff ); progStr = (*env)->NewStringUTF(env, progBuf); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else printf( "%s: %d*%d > %d*%d: %s %+d\n", MSG[I_MEASURES], width, height, vert? width: width + diff, vert? height + diff: height, vert? MSG[I_VERT]: MSG[I_HORI], diff ); #endif /* Hier kommt Fugenschnitzer zum Einsatz. * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ****************/ sc_init(); sc_load(image, &width, &height, 0); const int prep = sc_prepare( vert, diff, // Bild ggf. erweitern false, alpha? MARK_ALPHA: MARK_KEEP, // Ggf. Alpha-Markierung (mark_t*)NULL, // keine Markierung sonst &width, &height, &pwidth, &pheight ); if (prep < 0) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); free(row); return EXIT_FAILURE; } if (prep & 2) { #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[E_ALPHA]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else puts(MSG[E_ALPHA]); #endif } // Bildspeicher erweitern, falls das Bild vergroessert wurde: if (prep & 1) { image = realloc(image, (size_t)width * (size_t)height * sizeof(comp_t)); if (image == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); return EXIT_FAILURE; } if (vert) { row = realloc(row, (size_t)height * sizeof(comp_t*)); if (row == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); return EXIT_FAILURE; } } } pthread_t seam_th; pthread_create(&seam_th, NULL, seam_progress, (void*)(&diff)); // sc_seam(diff); seam_paral(diff); pthread_join(seam_th, NULL); #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[I_RESIZING]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else putchar('\n'); printf(MSG[I_RESIZING]); #endif // sc_carve(diff, &width, &height, &pwidth, &pheight); carve_paral(diff, &width, &height, &pwidth, &pheight); sc_fix( false, // Nicht wiederherstellen &width, &height, &pwidth, &pheight ); sc_eject(image); sc_close(); /* Das war's mit Fugenschnitzer. -- Zeilenzeiger neu setzen. **************/ rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Zieldatei oeffnen und Schreibvorgang initialisieren. ********************/ #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[I_SAVE]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else putchar('\n'); printf(MSG[I_SAVE]); #endif f = fopen(outname, "wb"); if (f == NULL) { fputs(outname, stderr); fputs(MSG[E_SAVE], stderr); fputc('\n', stderr); return EXIT_FAILURE; } png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); try_png_write(info_ptr == NULL, &png_ptr, &info_ptr, f, (char*)NULL); try_png_write( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, f, MSG[E_WRITE] ); png_init_io(png_ptr, f); /* Bildparameter setzen. **************************************************/ png_set_IHDR( png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); if (image_is_pal) png_set_PLTE(png_ptr, info_ptr, png_pal, num_palette); if (alpha) png_set_bKGD(png_ptr, info_ptr, &background); png_write_info(png_ptr, info_ptr); /* Falls 8 oder 16 bpp, Bilddaten wieder zusammenschieben. ****************/ trw = realloc(trw, image_is_gray? (width * 2): width); try_png_write(trw == NULL, &png_ptr, &info_ptr, f, (char*)NULL); if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } /* Bild speichern. Wieder Alpha invertieren (hoher Wert => hohe Transparenz) * sowie mit "png_set_filler" 32/16 bpp => 24/8 bpp setzen. ***************/ if (alpha) png_set_invert_alpha(png_ptr); else png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_write_image(png_ptr, (void*)row); png_write_end(png_ptr, (png_info*)NULL); #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[I_FINISHED]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 2); #else puts(MSG[I_FINISHED]); #endif /* Schreibvorgang beenden, Datei schliessen, Speicher freigeben, fertig. ***/ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); free(trw); free(image); free(row); #ifdef ANDROID_BUILD progStr = (*env)->NewStringUTF(env, MSG[I_COMPLETED]); (*env)->CallVoidMethod(env, pMainActObj, updateProgMID, progStr, 0); #else puts(MSG[I_COMPLETED]); #endif #ifdef ANDROID_BUILD (*env)->ReleaseStringUTFChars(env, pCmdStr, cmdstr); (*env)->DeleteGlobalRef(env, cachedMainActObj); cachedMainActObj = NULL; #endif return EXIT_SUCCESS; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; int color_type; int bit_depth; int pixel_depth = 0; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; png_bytepp row_pointers = NULL; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); // configure the decoder FREE_IMAGE_TYPE image_type = FIT_BITMAP; if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // update image info color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); // create a dib and write the bitmap header // set up the dib palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib) { png_colorp png_palette = NULL; int palette_entries = 0; png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); // store the palette RGBQUAD *palette = FreeImage_GetPalette(dib); for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib && (pixel_depth <= 8)) { RGBQUAD *palette = FreeImage_GetPalette(dib); const int palette_entries = 1 << pixel_depth; for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < 256) { BYTE table[256]; memset(table, 0xFF, 256); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, 256); } // check for a full transparency table, too else if ((trans_alpha) && (pixel_depth <= 8)) { FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color (only supported for FIT_BITMAP types) if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
int APIENTRY pngLoadF(FILE *fp, int mipmap, int trans, pngInfo *pinfo) { GLint pack, unpack; unsigned char header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep data, data2; png_bytep *row_p; double fileGamma; png_uint_32 width, height, rw, rh; int depth, color; png_uint_32 i; if (fread(header, 1, 8, fp) != 8 || !png_check_sig(header, 8)) return 0; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); endinfo = png_create_info_struct(png); /* DH: added following lines */ if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &info, &endinfo); return 0; } /* ~DH */ png_init_io(png, fp); png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); if (pinfo != NULL) { pinfo->Width = width; pinfo->Height = height; pinfo->Depth = depth; } if (MaxTextureSize == 0) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize); #ifdef SUPPORTS_PALETTE_EXT #ifdef _WIN32 if (PalettedTextures == -1) PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL); if (PalettedTextures) { if (glColorTableEXT == NULL) { glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT"); if (glColorTableEXT == NULL) PalettedTextures = 0; } } #endif #endif if (PalettedTextures == -1) PalettedTextures = 0; if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) { png_set_strip_alpha(png); color &= ~PNG_COLOR_MASK_ALPHA; } if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID)) if (color == PNG_COLOR_TYPE_PALETTE) png_set_expand(png); /*--GAMMA--*/ checkForGammaEnv(); if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); data = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i]; else row_p[i] = &data[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); rw = SafeSize(width), rh = SafeSize(height); if (rw != width || rh != height) { const int channels = png_get_rowbytes(png, info)/width; data2 = (png_bytep) malloc(rw*rh*channels); /* Doesn't work on certain sizes */ /* if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0) return 0; */ Resize(channels, data, width, height, data2, rw, rh); width = rw, height = rh; free(data); data = data2; } { /* OpenGL stuff */ glGetIntegerv(GL_PACK_ALIGNMENT, &pack); glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifdef SUPPORTS_PALETTE_EXT if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) { png_colorp pal; int cols; GLint intf; if (pinfo != NULL) pinfo->Alpha = 0; png_get_PLTE(png, info, &pal, &cols); switch (cols) { case 1<<1: intf = GL_COLOR_INDEX1_EXT; break; case 1<<2: intf = GL_COLOR_INDEX2_EXT; break; case 1<<4: intf = GL_COLOR_INDEX4_EXT; break; case 1<<8: intf = GL_COLOR_INDEX8_EXT; break; case 1<<12: intf = GL_COLOR_INDEX12_EXT; break; case 1<<16: intf = GL_COLOR_INDEX16_EXT; break; default: /*printf("Warning: Colour depth %i not recognised\n", cols);*/ return 0; } glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal); glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data); } else #endif if (trans == PNG_SOLID || trans == PNG_ALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) { GLenum glformat; GLint glcomponent; switch (color) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: glformat = GL_RGB; glcomponent = 3; if (pinfo != NULL) pinfo->Alpha = 0; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA: glformat = GL_RGBA; glcomponent = 4; if (pinfo != NULL) pinfo->Alpha = 8; break; default: /*puts("glformat not set");*/ return 0; } if (mipmap == PNG_BUILDMIPMAPS) Build2DMipmaps(glcomponent, width, height, glformat, data, 1); else if (mipmap == PNG_SIMPLEMIPMAPS) Build2DMipmaps(glcomponent, width, height, glformat, data, 0); else glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data); } else { png_bytep p, endp, q; int r, g, b, a; p = data, endp = p+width*height*3; q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4); if (pinfo != NULL) pinfo->Alpha = 8; #define FORSTART \ do { \ r = *p++; /*red */ \ g = *p++; /*green*/ \ b = *p++; /*blue */ \ *q++ = r; \ *q++ = g; \ *q++ = b; #define FOREND \ q++; \ } while (p != endp); #define ALPHA *q switch (trans) { case PNG_CALLBACKT: FORSTART ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b); FOREND break; case PNG_STENCIL: FORSTART if (r == StencilRed && g == StencilGreen && b == StencilBlue) ALPHA = 0; else ALPHA = 255; FOREND break; case PNG_BLEND1: FORSTART a = r+g+b; if (a > 255) ALPHA = 255; else ALPHA = a; FOREND break; case PNG_BLEND2: FORSTART a = r+g+b; if (a > 255*2) ALPHA = 255; else ALPHA = a/2; FOREND break; case PNG_BLEND3: FORSTART ALPHA = (r+g+b)/3; FOREND break; case PNG_BLEND4: FORSTART a = r*r+g*g+b*b; if (a > 255) ALPHA = 255; else ALPHA = a; FOREND break; case PNG_BLEND5: FORSTART a = r*r+g*g+b*b; if (a > 255*2) ALPHA = 255; else ALPHA = a/2; FOREND break; case PNG_BLEND6: FORSTART a = r*r+g*g+b*b; if (a > 255*3) ALPHA = 255; else ALPHA = a/3; FOREND break; case PNG_BLEND7: FORSTART a = r*r+g*g+b*b; if (a > 255*255) ALPHA = 255; else ALPHA = (int) sqrt(a); FOREND break; } #undef FORSTART #undef FOREND #undef ALPHA if (mipmap == PNG_BUILDMIPMAPS) Build2DMipmaps(4, width, height, GL_RGBA, data2, 1); else if (mipmap == PNG_SIMPLEMIPMAPS) Build2DMipmaps(4, width, height, GL_RGBA, data2, 0); else glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2); free(data2); } glPixelStorei(GL_PACK_ALIGNMENT, pack); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); } /* OpenGL end */ png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); free(data); return 1; }
int PngImage::CreateImage(png_structp png_ptr, png_infop info_ptr) { int status = PNG_INVALID; width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); bpp = png_get_bit_depth(png_ptr, info_ptr); if (width > 0 && width < 32768 && height > 0 && height < 32768) { // true-color: if (bpp >= 24) { status = PNG_OK; if ( png_get_channels(png_ptr, info_ptr) == 4) alpha_loaded = true; image = new DWORD[width*height]; BYTE** rows = png_get_rows(png_ptr, info_ptr); for (DWORD row = 0; row < height; row++) { BYTE* p = rows[row]; for (DWORD col = 0; col < width; col++) { DWORD red = *p++; DWORD green = *p++; DWORD blue = *p++; DWORD alpha = 0xff; if ( png_get_channels(png_ptr, info_ptr) == 4) alpha = *p++; image[row*width+col] = (alpha << 24) | (red << 16) | (green << 8) | blue; } } } // paletted: else if (bpp == 8) { DWORD pal[256]; png_bytep trans_alpha; int num_trans; png_color_16p trans_color; png_colorp palette; int num_palette; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_trans > 0) alpha_loaded = true; for (int i = 0; i < 256; i++) { if (i < num_palette) { DWORD red = palette[i].red; DWORD green = palette[i].green; DWORD blue = palette[i].blue; DWORD alpha = 0xff; if (i < num_trans) alpha = trans_alpha[i]; pal[i] = (alpha << 24) | (red << 16) | (green << 8) | blue; } else { pal[i] = 0; } } image = new DWORD[width*height]; BYTE** rows = png_get_rows(png_ptr, info_ptr); for (DWORD row = 0; row < height; row++) { BYTE* p = rows[row]; for (DWORD col = 0; col < width; col++) { BYTE index = *p++; image[row*width+col] = pal[index]; } } } } return status; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette; int color_type, palette_entries; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { try { // check to see if the file is in fact a PNG file unsigned char png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) return NULL; // Bad signature // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) return NULL; // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = info_ptr->pixel_depth; // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; #ifndef FREEIMAGE_BIGENDIAN // turn on 16 bit byte swapping png_set_swap(png_ptr); #endif } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; #ifndef FREEIMAGE_BIGENDIAN // turn on 16 bit byte swapping png_set_swap(png_ptr); #endif } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #ifndef FREEIMAGE_BIGENDIAN // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) png_set_bgr(png_ptr); #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_expand(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #ifndef FREEIMAGE_BIGENDIAN // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw "PNG format not supported"; } // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; } // if this image has transparency, store the trns values png_bytep trans = NULL; int num_trans = 0; png_color_16p trans_values = NULL; png_uint_32 transparent_value = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) png_set_gamma(png_ptr, screen_gamma, gamma); // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA : dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE : dib = FreeImage_Allocate(width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette,&palette_entries); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) FreeImage_SetTransparencyTable(dib, (BYTE *)trans, num_trans); break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateT(image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (i * 255) / (palette_entries - 1); } } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) FreeImage_SetTransparencyTable(dib, (BYTE *)trans, num_trans); break; default: throw "PNG format not supported"; } // store the background color if(image_background) { FreeImage_SetBackgroundColor(dib, &rgbBkColor); } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = 0; png_get_pHYs(png_ptr,info_ptr,&res_x,&res_y,&res_unit_type); if (res_unit_type == 1) { BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib); bih->biXPelsPerMeter = res_x; bih->biYPelsPerMeter = res_y; } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_charp profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_Allocate) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { if (palette) png_free(png_ptr, palette); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table for (png_uint_32 k = 0; k < height; k++) row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) FreeImage_SetTransparent(dib, TRUE); else FreeImage_SetTransparent(dib, FALSE); // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (row_pointers) free(row_pointers); if (dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
g_error png_load(hwrbitmap *hbmp, const u8 *data, u32 datalen) { png_structp png_ptr; png_infop info_ptr; struct datablock d; png_bytep *row_pointers; png_uint_32 width, height; int bit_depth,colortype,interlace; int x,y; u8 r,g,b,a; pgcolor c; png_bytep p; g_error e; png_colorp palette; int num_palette; png_colorp pp; png_bytep trans; int num_trans = 0; #ifdef CONFIG_DITHER hwrdither dither; #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ } /* Set libpng error handler */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 71); /* Error reading PNG */ } /* Set libpng read handler */ d.data = data; d.length = datalen; png_set_read_fn(png_ptr, &d, (png_rw_ptr) &png_user_read_data); /* Read the png into memory */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &colortype, &interlace, NULL, NULL); if (colortype == PNG_COLOR_TYPE_PALETTE) { png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); } if (interlace != PNG_INTERLACE_NONE) fprintf(stderr, "png loader: OOPS... interlaced image, will b0rk\n"); /* Allocate the picogui bitmap * * Important note: normally we create bitmaps at the display's * color depth, but if we have an alpha channel * we need room for ARGB colors. */ if (colortype == PNG_COLOR_TYPE_GRAY_ALPHA || colortype == PNG_COLOR_TYPE_RGB_ALPHA || num_trans) e = vid->bitmap_new(hbmp,width,height,32); else e = vid->bitmap_new(hbmp,width,height,vid->bpp); if (iserror(e)) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); errorcheck; #ifdef CONFIG_DITHER /* Start dithering */ e = vid->dither_start(&dither, *hbmp, 0,0,0,width,height); errorcheck; #endif /* Transcribe it into a picogui bitmap. * This method is slow, but ensures compatibility */ for (y=0;y<height;y++) { p = row_pointers[y]; for (x=0;x<width;x++) { switch (colortype) { case PNG_COLOR_TYPE_GRAY: g = *(p++); c = mkcolor(g,g,g); break; case PNG_COLOR_TYPE_GRAY_ALPHA: g = *(p++); a = *(p++); c = mkcolora(a>>1,g,g,g); break; case PNG_COLOR_TYPE_PALETTE: pp = &palette[ (*p) % num_palette ]; if (*p < num_trans) c = mkcolora(trans[*p]>>1, pp->red, pp->green, pp->blue); else if (num_trans) c = mkcolora(0x7f, pp->red, pp->green, pp->blue); else c = mkcolor(pp->red, pp->green, pp->blue); p++; break; case PNG_COLOR_TYPE_RGB: r = *(p++); g = *(p++); b = *(p++); c = mkcolor(r,g,b); break; case PNG_COLOR_TYPE_RGB_ALPHA: r = *(p++); g = *(p++); b = *(p++); a = *(p++); c = mkcolora(a>>1,r,g,b); break; } #ifdef CONFIG_DITHER vid->dither_store(dither, c, PG_LGOP_NONE); #else vid->pixel(*hbmp,x,y,VID(color_pgtohwr)(c),PG_LGOP_NONE); #endif } }
/* This routine is based in part on the Chapter 13 demo code in * "PNG: The Definitive Guide" (http://www.libpng.org/pub/png/book/). */ BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile) { png_byte sig[8]; #ifdef PNG_SETJMP_SUPPORTED jmpbuf_wrapper jbw; #endif png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height, rowbytes, w, h, res_x, res_y; int bit_depth, color_type, interlace_type, unit_type; int num_palette, num_trans; png_colorp palette; png_color_16p trans_gray_rgb; png_color_16p trans_color_rgb; png_bytep trans; png_bytep image_data = NULL; png_bytepp row_pointers = NULL; gdImagePtr im = NULL; int i, j, *open = NULL; volatile int transparent = -1; volatile int palette_allocated = FALSE; /* Make sure the signature can't match by dumb luck -- TBB */ /* GRR: isn't sizeof(infile) equal to the size of the pointer? */ memset (sig, 0, sizeof (sig)); /* first do a quick check that the file really is a PNG image; could * have used slightly more general png_sig_cmp() function instead */ if (gdGetBuf (sig, 8, infile) < 8) { return NULL; } if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */ return NULL; /* bad signature */ } #ifdef PNG_SETJMP_SUPPORTED png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL); #else png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif if (png_ptr == NULL) { gd_error("gd-png error: cannot allocate libpng main struct\n"); return NULL; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { gd_error("gd-png error: cannot allocate libpng info struct\n"); png_destroy_read_struct (&png_ptr, NULL, NULL); return NULL; } /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* setjmp() must be called in every non-callback function that calls a * PNG-reading libpng function */ #ifdef PNG_SETJMP_SUPPORTED if (setjmp(jbw.jmpbuf)) { gd_error("gd-png error: setjmp returns error condition 1\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } #endif png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ png_set_read_fn (png_ptr, (void *) infile, gdPngReadData); png_read_info (png_ptr, info_ptr); /* read all PNG info up to image data */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { im = gdImageCreateTrueColor ((int) width, (int) height); } else { im = gdImageCreate ((int) width, (int) height); } if (im == NULL) { gd_error("gd-png error: cannot allocate gdImage struct\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } if (bit_depth == 16) { png_set_strip_16 (png_ptr); } else if (bit_depth < 8) { png_set_packing (png_ptr); /* expand to 1 byte per pixel */ } /* setjmp() must be called in every non-callback function that calls a * PNG-reading libpng function */ #ifdef PNG_SETJMP_SUPPORTED if (setjmp(jbw.jmpbuf)) { gd_error("gd-png error: setjmp returns error condition 2\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); gdFree(image_data); gdFree(row_pointers); if (im) { gdImageDestroy(im); } return NULL; } #endif #ifdef PNG_pHYs_SUPPORTED /* check if the resolution is specified */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) { switch (unit_type) { case PNG_RESOLUTION_METER: im->res_x = DPM2DPI(res_x); im->res_y = DPM2DPI(res_y); break; } } } #endif switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette); #ifdef DEBUG gd_error("gd-png color_type is palette, colors: %d\n", num_palette); #endif /* DEBUG */ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { /* gd 2.0: we support this rather thoroughly now. Grab the * first fully transparent entry, if any, as the value of * the simple-transparency index, mostly for backwards * binary compatibility. The alpha channel is where it's * really at these days. */ int firstZero = 1; png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL); for (i = 0; i < num_trans; ++i) { im->alpha[i] = gdAlphaMax - (trans[i] >> 1); if ((trans[i] == 0) && (firstZero)) { /* 2.0.5: long-forgotten patch from Wez Furlong */ transparent = i; firstZero = 0; } } } break; case PNG_COLOR_TYPE_GRAY: /* create a fake palette and check for single-shade transparency */ if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) { gd_error("gd-png error: cannot allocate gray palette\n"); png_destroy_read_struct (&png_ptr, &info_ptr, NULL); return NULL; } palette_allocated = TRUE; if (bit_depth < 8) { num_palette = 1 << bit_depth; for (i = 0; i < 256; ++i) { j = (255 * i) / (num_palette - 1); palette[i].red = palette[i].green = palette[i].blue = j; } } else { num_palette = 256; for (i = 0; i < 256; ++i) { palette[i].red = palette[i].green = palette[i].blue = i; } } if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb); if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */ transparent = trans_gray_rgb->gray >> 8; } else { transparent = trans_gray_rgb->gray; } /* Note slight error in 16-bit case: up to 256 16-bit shades * may get mapped to a single 8-bit shade, and only one of them * is supposed to be transparent. IOW, both opaque pixels and * transparent pixels will be mapped into the transparent entry. * There is no particularly good way around this in the case * that all 256 8-bit shades are used, but one could write some * custom 16-bit code to handle the case where there are gdFree * palette entries. This error will be extremely rare in * general, though. (Quite possibly there is only one such * image in existence.) */ }
//int APIENTRY pngLoadRawF(FILE *fp, pngRawInfo *pinfo) { int pngLoadRaw(const char* filename, pngRawInfo *pinfo, vsxf* filesystem) { unsigned char header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep data; png_bytep *row_p; double fileGamma; vsxf_info i_filesystem; png_uint_32 width, height; int depth, color; png_uint_32 i; if (pinfo == NULL) { printf("error in png loader: pinfo is NULL %d\n",__LINE__); return 0; } i_filesystem.filesystem = filesystem; i_filesystem.fp = filesystem->f_open(filename,"rb"); if (!i_filesystem.fp) { printf("error in png loader: i_filesystem.fp not valid on line %d\n",__LINE__); return 0; } filesystem->f_read(header, 8, i_filesystem.fp); if (!png_check_sig(header, 8)) { printf("error in %s on line %d\n",__FILE__,__LINE__); return 0; } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { printf("error in %s on line %d\n",__FILE__,__LINE__); return 0; } info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png,(png_infopp)NULL,(png_infopp)NULL); printf("error in %s on line %d\n",__FILE__,__LINE__); return 0; } endinfo = png_create_info_struct(png); if (!endinfo) { png_destroy_read_struct(&png, &info, (png_infopp)NULL); printf("error in %s on line %d\n",__FILE__,__LINE__); return 0; } if (setjmp(png_jmpbuf(png))) { printf("error in png_jmpbuf %s on line %d\n",__FILE__,__LINE__); png_destroy_read_struct(&png, &info,&endinfo); filesystem->f_close(i_filesystem.fp); return 0; } png_set_read_fn(png, (png_bytep)(&i_filesystem), png_vsxf_read_data); png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); pinfo->Width = width; pinfo->Height = height; pinfo->Depth = depth; if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (color == PNG_COLOR_TYPE_PALETTE) png_set_expand(png); /*--GAMMA--*/ checkForGammaEnv(); if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); data = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i]; else row_p[i] = &data[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); if (color == PNG_COLOR_TYPE_PALETTE) { int cols; png_get_PLTE(png, info, (png_colorp *) &pinfo->Palette, &cols); } else { pinfo->Palette = NULL; } if (color&PNG_COLOR_MASK_ALPHA) { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY_ALPHA) pinfo->Components = 2; else pinfo->Components = 4; pinfo->Alpha = 8; } else { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY) pinfo->Components = 1; else pinfo->Components = 3; pinfo->Alpha = 0; } pinfo->Data = data; png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); filesystem->f_close(i_filesystem.fp); return 1; }
void * pngconv_png2lossless(unsigned char *png_data, unsigned long png_data_len, int *tag_no, int *format, unsigned short *width, unsigned short *height, void **colormap, int *colormap_count, int rgb15) { volatile png_structp png_ptr = NULL; volatile png_infop png_info_ptr = NULL; my_png_buffer png_buff; int bpp, color_type; png_uint_32 png_width = 0, png_height = 0; volatile png_bytepp png_image_data = NULL; register png_uint_32 x, y; void *image_data = NULL; png_color *palette = NULL; int palette_num = 0; png_bytep trans = NULL; int num_trans = 0; png_color_16p trans_values = NULL; if (png_data == NULL) { fprintf(stderr, "pngconv_png2lossless: png_data == NULL\n"); return NULL; } if (png_sig_cmp((png_bytep)png_data, 0, 8)) { // bad signature fprintf(stderr, "pngconv_png2lossless: is not PNG!\n"); return NULL; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (! png_ptr) { fprintf(stderr, "pngconv_png2lossless: can't create read_struct\n"); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "pngconv_png2lossless: libpng error jump occured\n"); png_destroy_read_struct((png_structpp) &png_ptr, (png_infopp) &png_info_ptr, NULL); if (png_image_data) { for (y=0 ; y < png_height ; y++) { free(png_image_data[y]); } free(png_image_data); } return NULL; } png_info_ptr = png_create_info_struct(png_ptr); if (! png_info_ptr) { fprintf(stderr, "pngconv_png2lossless: can't create info_struct\n"); png_destroy_read_struct ((png_structpp)&png_ptr, NULL, NULL); return NULL; } png_buff.data = png_data; png_buff.data_len = png_data_len; png_buff.data_offset = 0; png_data_read(png_ptr, &png_buff); png_read_info(png_ptr, png_info_ptr); png_get_IHDR(png_ptr, png_info_ptr, &png_width, &png_height, &bpp, &color_type, NULL, NULL, NULL); *width = (unsigned short) png_width; *height = (unsigned short) png_height; if ((rgb15 > 0) && (color_type != PNG_COLOR_TYPE_RGB)) { // warning fprintf(stderr, "rgb15 is %d but color_type is not PNG24\n", rgb15); } switch(color_type) { case PNG_COLOR_TYPE_PALETTE: *format = 3; png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_num); if (png_get_tRNS(png_ptr, png_info_ptr, &trans, &num_trans, &trans_values) && (num_trans > 0)) { *tag_no = 36; // DefineBitsLossless2 } else { *tag_no = 20; // DefineBitsLossless } break; case PNG_COLOR_TYPE_RGB: if (rgb15 > 0) { *format = 4; } else { *format = 5; } *tag_no = 20; /* DefineBitsLossless */ break; case PNG_COLOR_TYPE_RGB_ALPHA: *format = 5; *tag_no = 36; /* DefineBitsLossless2 */ if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); break; default: fprintf(stderr, "pngconv_png2lossless: color_type=%d not implemented yet.\n", color_type); png_destroy_read_struct((png_structpp)&png_ptr, (png_infopp)&png_info_ptr, NULL); return NULL; } if (bpp > 8) { fprintf(stderr, "pngconv_png2lossless: bpp=%d not implemented yet. accept only bpp <= 8\n", bpp); png_destroy_read_struct((png_structpp)&png_ptr, (png_infopp)&png_info_ptr, NULL); return NULL; } png_image_data = (png_bytepp) malloc(png_height * sizeof(png_bytep)); for (y=0 ; y < png_height ; y++) { png_image_data[y] = (png_bytep) malloc(png_get_rowbytes(png_ptr, png_info_ptr)); } png_read_image(png_ptr, png_image_data); /* * image copy */ if (color_type == PNG_COLOR_TYPE_PALETTE) { register int i; unsigned char *indices_data; *colormap_count = palette_num; if (num_trans == 0) { swf_rgb_t *result_colormap = malloc(sizeof(swf_rgb_t) * palette_num); // Lossless for (i=0 ; i < palette_num ; i++) { result_colormap[i].red = palette[i].red; result_colormap[i].green = palette[i].green; result_colormap[i].blue = palette[i].blue; } *colormap = result_colormap; } else { swf_rgba_t *result_colormap = malloc(sizeof(swf_rgba_t) * palette_num); // Lossless2 for (i=0 ; i < palette_num ; i++) { if (i < num_trans) { int alpha_value = trans[i]; result_colormap[i].red = palette[i].red * alpha_value / 0xff; result_colormap[i].green = palette[i].green * alpha_value / 0xff; result_colormap[i].blue = palette[i].blue * alpha_value / 0xff; result_colormap[i].alpha = alpha_value; } else { result_colormap[i].red = palette[i].red; result_colormap[i].green = palette[i].green; result_colormap[i].blue = palette[i].blue; result_colormap[i].alpha = 0xff; // opaque } } *colormap = result_colormap; } indices_data = malloc(((png_width+ 3) & -4) * png_height); i = 0; for (y=0 ; y < png_height ; y++) { bitstream_t *bs = bitstream_open(); if (bs == NULL) { free(*colormap); *colormap = NULL; free(indices_data); for (y=0 ; y < png_height ; y++) { free(png_image_data[y]); } free(png_image_data); return NULL; } bitstream_input(bs, png_image_data[y], png_width); for (x=0 ; x < png_width ; x++) { indices_data[i] = bitstream_getbits(bs, bpp); i++; } while (i % 4) { i++; } // 4byte alignment bitstream_close(bs); } image_data = indices_data; } else if (color_type == PNG_COLOR_TYPE_RGB) { swf_xrgb_t *xrgb_list; xrgb_list = malloc(sizeof(swf_xrgb_t) * png_width * png_height); for (y=0 ; y < png_height ; y++) { for (x=0 ; x < png_width ; x++) { xrgb_list[x+y*png_width].red = png_image_data[y][3*x + 0]; xrgb_list[x+y*png_width].green = png_image_data[y][3*x + 1]; xrgb_list[x+y*png_width].blue = png_image_data[y][3*x + 2]; } } image_data = xrgb_list; } else { // PNG_COLOR_TYPE_RGB_ALPHA swf_argb_t *argb_list; argb_list = malloc(sizeof(swf_argb_t) * png_width * png_height); for (y=0 ; y < png_height ; y++) { for (x=0 ; x < png_width ; x++) { int alpha_value = png_image_data[y][4*x + 3]; argb_list[x+y*png_width].red = png_image_data[y][4*x + 0] * alpha_value / 0xff; argb_list[x+y*png_width].green = png_image_data[y][4*x + 1] * alpha_value / 0xff; argb_list[x+y*png_width].blue = png_image_data[y][4*x + 2] * alpha_value / 0xff; argb_list[x+y*png_width].alpha = alpha_value; } } image_data = argb_list; } for (y=0 ; y < png_height ; y++) { free(png_image_data[y]); } free(png_image_data); /* * destruct */ png_destroy_read_struct((png_structpp) &png_ptr, (png_infopp) &png_info_ptr, NULL); return image_data; }
static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, float screen_gamma=0.0) { if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma(png_ptr, screen_gamma, file_gamma); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_bytep trans_alpha = 0; png_color_16p trans_color_p = 0; int num_trans; png_colorp palette = 0; int num_palette; int interlace_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0); png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { image = QImage(width, height, QImage::Format_Mono); if (image.isNull()) return; } image.setColorCount(2); image.setColor(1, qRgb(0,0,0)); image.setColor(0, qRgb(255,255,255)); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { image = QImage(width, height, QImage::Format_ARGB32); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) { image = QImage(width, height, QImage::Format_Indexed8); if (image.isNull()) return; } image.setColorCount(ncols); for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); image.setColorCount(num_palette); int i = 0; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { while (i < num_trans) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, trans_alpha[i] ) ); i++; } } while (i < num_palette) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); QImage::Format format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } QSize outSize(width,height); if (!scaledSize.isEmpty() && quint32(scaledSize.width()) <= width && quint32(scaledSize.height()) <= height && interlace_method == PNG_INTERLACE_NONE) { // Do inline downscaling outSize = scaledSize; if (doScaledRead) *doScaledRead = true; } if (image.size() != outSize || image.format() != format) { image = QImage(outSize, format); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { png_set_bgr(png_ptr); } }
int loadPNG(ePtr<gPixmap> &result, const char *filename) { __u8 header[8]; FILE *fp=fopen(filename, "rb"); if (!fp) { // eDebug("couldn't open %s", filename ); return 0; } if (!fread(header, 8, 1, fp)) { eDebug("couldn't read"); fclose(fp); return 0; } if (png_sig_cmp(header, 0, 8)) { fclose(fp); return 0; } png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { eDebug("no pngptr"); fclose(fp); return 0; } png_infop info_ptr=png_create_info_struct(png_ptr); if (!info_ptr) { eDebug("no info ptr"); png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); fclose(fp); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { eDebug("no end"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return 0; } #if (PNG_LIBPNG_VER < 10500) if (setjmp(png_ptr->jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { eDebug("das war wohl nix"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); result = 0; return 0; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_set_invert_alpha(png_ptr); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth; int color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY || color_type & PNG_COLOR_MASK_PALETTE) { result=new gPixmap(eSize(width, height), bit_depth); gSurface *surface = result->surface; png_bytep *rowptr=new png_bytep[height]; for (unsigned int i=0; i<height; i++) rowptr[i]=((png_byte*)(surface->data))+i*surface->stride; png_read_rows(png_ptr, rowptr, 0, height); delete [] rowptr; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_color *palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette) surface->clut.data=new gRGB[num_palette]; else surface->clut.data=0; surface->clut.colors=num_palette; for (int i=0; i<num_palette; i++) { surface->clut.data[i].a=0; surface->clut.data[i].r=palette[i].red; surface->clut.data[i].g=palette[i].green; surface->clut.data[i].b=palette[i].blue; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_byte *trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0); for (int i=0; i<num_palette; i++) surface->clut.data[i].a=255-trans[i]; } } else { surface->clut.data=0; surface->clut.colors=0; } surface->clut.start=0; png_read_end(png_ptr, end_info); } else { result=0; eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type); } png_destroy_read_struct(&png_ptr, &info_ptr,&end_info); fclose(fp); return 0; }
bool wxPNGHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) { // VZ: as this function uses setjmp() the only fool-proof error handling // method is to use goto (setjmp is not really C++ dtors friendly...) unsigned char **lines = NULL; png_infop info_ptr = (png_infop) NULL; wxPNGInfoStruct wxinfo; png_uint_32 i, width, height = 0; int bit_depth, color_type, interlace_type; wxinfo.verbose = verbose; wxinfo.stream.in = &stream; image->Destroy(); png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, wx_PNG_error, wx_PNG_warning ); if (!png_ptr) goto error; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) goto error; if (setjmp(wxinfo.jmpbuf)) goto error; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->IsOk()) goto error; // initialize all line pointers to NULL to ensure that they can be safely // free()d if an error occurs before all of them could be allocated lines = (unsigned char **)calloc(height, sizeof(unsigned char *)); if ( !lines ) goto error; for (i = 0; i < height; i++) { if ((lines[i] = (unsigned char *)malloc( (size_t)(width * 4))) == NULL) goto error; } png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { png_colorp palette = NULL; int numPalette = 0; (void) png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); unsigned char* r = new unsigned char[numPalette]; unsigned char* g = new unsigned char[numPalette]; unsigned char* b = new unsigned char[numPalette]; for (int j = 0; j < numPalette; j++) { r[j] = palette[j].red; g[j] = palette[j].green; b[j] = palette[j].blue; } image->SetPalette(wxPalette(numPalette, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE // set the image resolution if it's available png_uint_32 resX, resY; int unitType; if (png_get_pHYs(png_ptr, info_ptr, &resX, &resY, &unitType) == PNG_INFO_pHYs) { wxImageResolution res = wxIMAGE_RESOLUTION_CM; switch (unitType) { default: wxLogWarning(_("Unknown PNG resolution unit %d"), unitType); wxFALLTHROUGH; case PNG_RESOLUTION_UNKNOWN: image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, resX); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, resY); res = wxIMAGE_RESOLUTION_NONE; break; case PNG_RESOLUTION_METER: /* Convert meters to centimeters. Use a string to not lose precision (converting to cm and then to inch would result in integer rounding error). If an app wants an int, GetOptionInt will convert and round down for them. */ image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, wxString::FromCDouble((double) resX / 100.0, 2)); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, wxString::FromCDouble((double) resY / 100.0, 2)); break; } image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, res); } png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); for ( i = 0; i < height; i++ ) free( lines[i] ); free( lines ); return true; error: if (verbose) { wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); } if ( image->IsOk() ) { image->Destroy(); } if ( lines ) { for ( unsigned int n = 0; n < height; n++ ) free( lines[n] ); free( lines ); } if ( png_ptr ) { if ( info_ptr ) { png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); free(info_ptr); } else png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); } return false; }
int ExtractBits(PNG_CONST TCHAR *inname, PNG_CONST TCHAR *outname) { static HANDLE fpin; static HANDLE fpout; /* "static" prevents setjmp corruption */ png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; png_infop write_end_info_ptr = NULL; png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; int num_pass, pass; int bit_depth, color_type; char inbuf[256], outbuf[256]; row_buf = NULL; if ((fpin = CreateFile(inname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find input file %s\n", inname); return (1); } if ((fpout = CreateFile(outname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not open output file %s\n", outname); FCLOSE(fpin); return (1); } png_debug(0, "Allocating read and write structures"); read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL); png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); png_debug(0, "Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); end_info_ptr = png_create_info_struct(read_ptr); png_debug(0, "Setting jmpbuf for read struct"); if (setjmp(png_jmpbuf(read_ptr))) { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); row_buf = NULL; png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); FCLOSE(fpin); FCLOSE(fpout); return (1); } png_debug(0, "Initializing input and output streams"); png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); if (status_dots_requested == 1) { png_set_read_status_fn(read_ptr, read_row_callback); } else { png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); } png_debug(0, "Reading info struct"); png_read_info(read_ptr, read_info_ptr); png_debug(0, "Transferring info struct"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type); } } { int intent; if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) png_set_sRGB(write_ptr, write_info_ptr, intent); } { png_colorp palette; int num_palette; if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); } { png_color_8p sig_bit; if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) png_set_sBIT(write_ptr, write_info_ptr, sig_bit); } { png_bytep trans; int num_trans; png_color_16p trans_values; if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, &trans_values)) { int sample_max = (1 << read_info_ptr->bit_depth); /* libpng doesn't reject a tRNS chunk with out-of-range samples */ if (!((read_info_ptr->color_type == PNG_COLOR_TYPE_GRAY && (int)trans_values->gray > sample_max) || (read_info_ptr->color_type == PNG_COLOR_TYPE_RGB && ((int)trans_values->red > sample_max || (int)trans_values->green > sample_max || (int)trans_values->blue > sample_max)))) png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, trans_values); } } png_debug(0, "Writing row data"); num_pass = png_set_interlace_handling(read_ptr); for(pass = 0; pass < num_pass; pass++) { png_debug1(0, "Writing row data for pass %d", pass); for(y = 0; y < height; y++) { png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); row_buf = (png_bytep)png_malloc(read_ptr, png_get_rowbytes(read_ptr, read_info_ptr)); png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, png_get_rowbytes(read_ptr, read_info_ptr)); png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); png_free(read_ptr, row_buf); row_buf = NULL; } } png_debug(0, "Reading and writing end_info data"); png_read_end(read_ptr, end_info_ptr); { png_uint_32 iwidth, iheight; iwidth = png_get_image_width(write_ptr, write_info_ptr); iheight = png_get_image_height(write_ptr, write_info_ptr); fprintf(STDERR, "\n Image width = %lu, height = %lu\n", (unsigned long)iwidth, (unsigned long)iheight); } png_debug(0, "Destroying data structs"); png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_debug(0, "Destruction complete."); FCLOSE(fpin); FCLOSE(fpout); png_debug(0, "Opening files for comparison"); if ((fpin = CreateFile(inname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find file %s\n", inname); return (1); } if ((fpout = CreateFile(outname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find file %s\n", outname); FCLOSE(fpin); return (1); } for(;;) { DWORD num_in, num_out; READFILE(fpin, inbuf, 1, num_in); READFILE(fpout, outbuf, 1, num_out); if (num_in != num_out) { fprintf(STDERR, "\nFiles %s and %s are of a different size\n", inname, outname); if (wrote_question == 0) { fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", inname, PNG_ZBUF_SIZE); fprintf(STDERR, "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, " level (zlib default),\n and zlib version (%s)?\n\n", ZLIB_VERSION); wrote_question = 1; } FCLOSE(fpin); FCLOSE(fpout); return (0); } if (!num_in) break; if (png_memcmp(inbuf, outbuf, num_in)) { fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); if (wrote_question == 0) { fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", inname, PNG_ZBUF_SIZE); fprintf(STDERR, "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, " level (zlib default),\n and zlib version (%s)?\n\n", ZLIB_VERSION); wrote_question = 1; } FCLOSE(fpin); FCLOSE(fpout); return (0); } } FCLOSE(fpin); FCLOSE(fpout); return (0); }
void DisplaySplashImage() { FILE *f = FioFOpenFile(SPLASH_IMAGE_FILE); if (f == NULL) return; png_byte header[8]; fread(header, sizeof(png_byte), 8, f); if (png_sig_cmp(header, 0, 8) != 0) { fclose(f); return; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(f); return; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(f); return; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); uint bit_depth = png_get_bit_depth(png_ptr, info_ptr); uint color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); if (width > (uint) _screen.width) width = _screen.width; if (height > (uint) _screen.height) height = _screen.height; uint xoff = (_screen.width - width) / 2; uint yoff = (_screen.height - height) / 2; switch (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()) { case 8: { uint8 *dst_ptr = (uint8 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0xff, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint8 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; memcpy(dst, src, width); } for (int i = 0; i < num_palette; i++) { _cur_palette[i].a = i == 0 ? 0 : 0xff; _cur_palette[i].r = palette[i].red; _cur_palette[i].g = palette[i].green; _cur_palette[i].b = palette[i].blue; } _cur_palette[0xff].a = 0xff; _cur_palette[0xff].r = 0; _cur_palette[0xff].g = 0; _cur_palette[0xff].b = 0; _pal_first_dirty = 0; _pal_count_dirty = 256; } break; case 32: { uint32 *dst_ptr = (uint32 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint32 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; for (uint x = 0; x < width; x++) { dst[x] = palette[src[x]].blue | (palette[src[x]].green << 8) | (palette[src[x]].red << 16) | 0xff000000; } } } break; } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; }
static int pgeTextureLoadPngInternal(png_structp png_ptr, pgeTexture* texture) { png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; unsigned int y; png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn); info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { debugOut("1\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_set_strip_16(png_ptr); png_set_packing(png_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); if(width > 512 || height > 512) { debugOut("2\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } texture->palette = 0; int i; switch(color_type) { case PNG_COLOR_TYPE_GRAY: texture->format = PGE_PIXEL_FORMAT_T8; texture->bits = 8; if(bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); texture->palette = pgeMalloc(1024); texture->palFormat = PGE_PIXEL_FORMAT_8888; if(texture->palette == 0) { debugOut("3\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } for(i = 0;i < 256;i++) ((int*)texture->palette)[i] = ((0xFF << 24) | (i << 16) | (i << 8) | i); break; case PNG_COLOR_TYPE_PALETTE: texture->format = PGE_PIXEL_FORMAT_T8; texture->bits = 8; texture->palette = pgeMalloc(1024); //256 * 4 texture->palFormat = PGE_PIXEL_FORMAT_8888; if(texture->palette == 0) { debugOut("4\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } png_colorp palette = NULL; png_bytep trans = NULL; int num_palette = 0; int num_trans = 0; png_color_16p trans_values; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); int col; for(i = 0; i < num_palette; i++) { col = (palette[i].red) | (palette[i].green << 8) | (palette[i].blue << 16); if(trans != NULL && i < num_trans) { col |= trans[i] << 24; } else { col |= 0xff000000; } ((int*)texture->palette)[i] = col; } break; case PNG_COLOR_TYPE_RGB: if(!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); else png_set_tRNS_to_alpha(png_ptr); case PNG_COLOR_TYPE_RGB_ALPHA: texture->format = PGE_PIXEL_FORMAT_8888; texture->bits = 32; break; default: debugOut("5\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } texture->swizzled = 0; texture->width = width; texture->height = height; texture->textureHeight = pgeTextureNextPow2(height); texture->textureWidth = pgeTextureNextPow2(width); if(texture->textureHeight < 8) texture->textureHeight = 8; if(texture->textureWidth < 16) texture->textureWidth = 16; texture->size = texture->textureWidth*pgeTextureNextMul8(texture->height)*(texture->bits>>3); texture->data = pgeMalloc(texture->size); memset(texture->data, 0xFF, texture->size); if(texture->data == 0) { debugOut("6\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return 0; } unsigned char* dst = (unsigned char*)texture->data; for(y = 0; y < height; y++) { png_read_row(png_ptr, (unsigned char*)dst, png_bytep_NULL); dst += (texture->textureWidth)*(texture->bits>>3); } png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); return 1; }
int kd_read_png8(const char *filename,int *w,int *h,int *bpp,kate_color **palette,int *ncolors,unsigned char **pixels) { FILE *f=NULL; png_structp png_ptr=NULL; png_infop info_ptr=NULL; int cdepth,ctype; int channels; int width,height; png_bytep *row_pointers=NULL; int transforms=PNG_TRANSFORM_STRIP_16; png_colorp png_palette; int x,y,n,num_palette; png_bytep trans; int num_trans; int has_trans; f=kd_open(filename); if (!f) return -1; png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (!png_ptr) { fprintf(stderr,"Cannot created PNG read structure\n"); goto error; } info_ptr=png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr,"Cannot created PNG info structure\n"); goto error; } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr,"PNG read failed\n"); goto error; } png_init_io(png_ptr,f); png_set_sig_bytes(png_ptr,8); png_read_png(png_ptr,info_ptr,transforms,NULL); channels=png_get_channels(png_ptr,info_ptr); if (channels!=1) { fprintf(stderr,"Channels is not 1 (%d)",channels); goto error; } ctype=png_get_color_type(png_ptr,info_ptr); if (!(ctype&PNG_COLOR_MASK_PALETTE)) { fprintf(stderr,"Image is not paletted\n"); goto error; } if (!(ctype&PNG_COLOR_MASK_COLOR)) { fprintf(stderr,"Image does not contain color information\n"); goto error; } cdepth=png_get_bit_depth(png_ptr,info_ptr); if (cdepth>8) { fprintf(stderr,"Color depth is higher than 8\n"); goto error; } width=png_get_image_width(png_ptr,info_ptr); height=png_get_image_height(png_ptr,info_ptr); if (!png_get_PLTE(png_ptr,info_ptr,&png_palette,&num_palette)) { fprintf(stderr,"Failed to retrieve palette data\n"); goto error; } /* this may or may not be there */ has_trans=(png_get_tRNS(png_ptr,info_ptr,&trans,&num_trans,NULL)&PNG_INFO_tRNS); row_pointers=png_get_rows(png_ptr,info_ptr); if (!row_pointers) { fprintf(stderr,"Failed to retrieve image data\n"); goto error; } /* allocate memory */ if (palette) { *palette=(kate_color*)kate_malloc(num_palette*sizeof(kate_color)); if (!*palette) { fprintf(stderr,"Not enough memory to allocate space for palette (%d colors)\n",num_palette); goto error; } } if (pixels) { *pixels=(unsigned char*)kate_malloc(width*height); if (!*pixels) { fprintf(stderr,"Not enough memory to allocate space for pixels (%dx%d)\n",width,height); if (palette) kate_free(*palette); goto error; } } /* fill data */ if (w) *w=width; if (h) *h=height; if (bpp) *bpp=cdepth; if (palette) { for (n=0;n<num_palette;++n) { (*palette)[n].r=png_palette[n].red; (*palette)[n].g=png_palette[n].green; (*palette)[n].b=png_palette[n].blue; (*palette)[n].a=(has_trans && n<num_trans)?trans[n]:255; } } if (ncolors) *ncolors=num_palette; if (pixels) { /* the PNG_TRANSFORM_PACKING and PNG_TRANSFORM_PACKSWAP bits don't seem to do anything to my 4 bit images, so do it by hand */ int ppb=8/cdepth; int mask=(1<<cdepth)-1; n=0; for (y=0;y<height;++y) { unsigned char *row=row_pointers[y]; for (x=0;x<width;++x) { (*pixels)[n++]=(row[x/ppb]>>((ppb-1-x%ppb)*cdepth))&mask; } } } png_destroy_read_struct(&png_ptr,&info_ptr,NULL); fclose(f); return 0; error: if (png_ptr) png_destroy_read_struct(&png_ptr,info_ptr?&info_ptr:NULL,NULL); if (f) fclose(f); return -1; }
int read_png(FILE *file, int filetype, F_pic *pic) { register int i, j; png_structp png_ptr; png_infop info_ptr; png_infop end_info; png_uint_32 w, h, rowsize; int bit_depth, color_type, interlace_type; int compression_type, filter_type; png_bytep *row_pointers; char *ptr; int num_palette; png_colorp palette; png_color_16 background; /* make scale factor smaller for metric */ float scale = (appres.INCHES ? (float)PIX_PER_INCH : 2.54*PIX_PER_CM)/(float)DISPLAY_PIX_PER_INCH; /* read the png file here */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); if (!png_ptr) { close_picfile(file,filetype); return FileInvalid; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); close_picfile(file,filetype); return FileInvalid; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); close_picfile(file,filetype); return FileInvalid; } /* set long jump recovery here */ if (setjmp(png_ptr->jmpbuf)) { /* if we get here there was a problem reading the file */ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); close_picfile(file,filetype); return FileInvalid; } /* set up the input code */ png_init_io(png_ptr, file); /* now read the file info */ png_read_info(png_ptr, info_ptr); /* get width, height etc */ png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (info_ptr->valid & PNG_INFO_gAMA) png_set_gamma(png_ptr, 2.2, info_ptr->gamma); else png_set_gamma(png_ptr, 2.2, 0.45); if (info_ptr->valid & PNG_INFO_bKGD) /* set the background to the one supplied */ png_set_background(png_ptr, &info_ptr->background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else { /* blend the canvas background using the alpha channel */ background.red = x_bg_color.red >> 8; background.green = x_bg_color.green >> 8; background.blue = x_bg_color.blue >> 8; background.gray = 0; png_set_background(png_ptr, &background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 2.2); } /* set order to BGR (default is RGB) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); /* strip 16-bit RGB values down to 8-bit */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* force to 8-bits per pixel if less than 8 */ if (bit_depth < 8) png_set_packing(png_ptr); /* dither rgb files down to 8 bit palette */ num_palette = 0; pic->pic_cache->transp = TRANSP_NONE; if (color_type & PNG_COLOR_MASK_COLOR) { png_uint_16p histogram; #ifdef USE_ALPHA /* we need to somehow give libpng a background color that it can combine with the alpha information in each pixel to make the image */ if (color_type & PNG_COLOR_MASK_ALPHA) pic->pic_cache->transp = TRANSP_BACKGROUND; #endif /* USE_ALPHA */ if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { png_get_hIST(png_ptr, info_ptr, &histogram); png_set_dither(png_ptr, palette, num_palette, 256, histogram, 0); } } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { /* expand to full range */ png_set_expand(png_ptr); /* make a gray colormap */ num_palette = 256; for (i = 0; i < num_palette; i++) pic->pic_cache->cmap[i].red = pic->pic_cache->cmap[i].green = pic->pic_cache->cmap[i].blue = i; } else { /* transfer the palette to the object's colormap */ for (i=0; i<num_palette; i++) { pic->pic_cache->cmap[i].red = palette[i].red; pic->pic_cache->cmap[i].green = palette[i].green; pic->pic_cache->cmap[i].blue = palette[i].blue; } } rowsize = w; if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) rowsize = w*3; /* allocate the row pointers and rows */ row_pointers = (png_bytep *) malloc(h*sizeof(png_bytep)); for (i=0; i<h; i++) { if ((row_pointers[i] = malloc(rowsize)) == NULL) { for (j=0; j<i; j++) free(row_pointers[j]); close_picfile(file,filetype); return FileInvalid; } } /* finally, read the file */ png_read_image(png_ptr, row_pointers); /* allocate the bitmap */ if ((pic->pic_cache->bitmap=malloc(rowsize*h))==NULL) { close_picfile(file,filetype); return FileInvalid; } /* copy it to our bitmap */ ptr = pic->pic_cache->bitmap; for (i=0; i<h; i++) { bcopy(row_pointers[i], ptr, rowsize); ptr += rowsize; } /* put in width, height */ pic->pic_cache->bit_size.x = w; pic->pic_cache->bit_size.y = h; if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { /* no palette, must use neural net to reduce to 256 colors with palette */ if (!map_to_palette(pic)) { close_picfile(file,filetype); return FileInvalid; /* out of memory or something */ } pic->pic_cache->numcols = 256; } else { pic->pic_cache->numcols = num_palette; } /* clean up */ png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); for (i=0; i<h; i++) free(row_pointers[i]); pic->pic_cache->subtype = T_PIC_PNG; pic->pixmap = None; pic->hw_ratio = (float) pic->pic_cache->bit_size.y / pic->pic_cache->bit_size.x; pic->pic_cache->size_x = pic->pic_cache->bit_size.x * scale; pic->pic_cache->size_y = pic->pic_cache->bit_size.y * scale; /* if monochrome display map bitmap */ if (tool_cells <= 2 || appres.monochrome) map_to_mono(pic); close_picfile(file,filetype); return PicSuccess; }
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header. // Bits (if set indicates existence of the chunk): // 0 - gAMA // 1 - sBIT // 2 - cHRM // 3 - PLTE // 4 - tRNS // 5 - bKGD // 6 - hIST // 7 - pHYs // 8 - oFFs // 9 - tIME // 10 - pCAL // 11 - sRGB // 12 - iCCP // 13 - sPLT // 14 - sCAL // 15 - IDAT // 16:30 - reserved be_t<u32> pngDecGetChunkInformation(PngStream* stream, bool IDAT = false) { // The end result of the chunk information (bigger-endian) be_t<u32> chunk_information = 0; // Needed pointers for getting the chunk information f64 gamma; f64 red_x; f64 red_y; f64 green_x; f64 green_y; f64 blue_x; f64 blue_y; f64 white_x; f64 white_y; f64 width; f64 height; s32 intent; s32 num_trans; s32 num_palette; s32 unit_type; s32 type; s32 nparams; s32 compression_type; s32 unit; u16* hist; png_uint_32 proflen; iCCP_profile_type profile; png_bytep trans_alpha; png_charp units; png_charp name; png_charp purpose; png_charpp params; png_int_32 X0; png_int_32 X1; png_int_32 offset_x; png_int_32 offset_y; png_uint_32 res_x; png_uint_32 res_y; png_colorp palette; png_color_8p sig_bit; png_color_16p background; png_color_16p trans_color; png_sPLT_tp entries; png_timep mod_time; // Get chunk information and set the appropriate bits if (png_get_gAMA(stream->png_ptr, stream->info_ptr, &gamma)) { chunk_information |= 1 << 0; // gAMA } if (png_get_sBIT(stream->png_ptr, stream->info_ptr, &sig_bit)) { chunk_information |= 1 << 1; // sBIT } if (png_get_cHRM(stream->png_ptr, stream->info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { chunk_information |= 1 << 2; // cHRM } if (png_get_PLTE(stream->png_ptr, stream->info_ptr, &palette, &num_palette)) { chunk_information |= 1 << 3; // PLTE } if (png_get_tRNS(stream->png_ptr, stream->info_ptr, &trans_alpha, &num_trans, &trans_color)) { chunk_information |= 1 << 4; // tRNS } if (png_get_bKGD(stream->png_ptr, stream->info_ptr, &background)) { chunk_information |= 1 << 5; // bKGD } if (png_get_hIST(stream->png_ptr, stream->info_ptr, &hist)) { chunk_information |= 1 << 6; // hIST } if (png_get_pHYs(stream->png_ptr, stream->info_ptr, &res_x, &res_y, &unit_type)) { chunk_information |= 1 << 7; // pHYs } if (png_get_oFFs(stream->png_ptr, stream->info_ptr, &offset_x, &offset_y, &unit_type)) { chunk_information |= 1 << 8; // oFFs } if (png_get_tIME(stream->png_ptr, stream->info_ptr, &mod_time)) { chunk_information |= 1 << 9; // tIME } if (png_get_pCAL(stream->png_ptr, stream->info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, ¶ms)) { chunk_information |= 1 << 10; // pCAL } if (png_get_sRGB(stream->png_ptr, stream->info_ptr, &intent)) { chunk_information |= 1 << 11; // sRGB } if (png_get_iCCP(stream->png_ptr, stream->info_ptr, &name, &compression_type, &profile, (png_uint_32*)&proflen)) { chunk_information |= 1 << 12; // iCCP } if (png_get_sPLT(stream->png_ptr, stream->info_ptr, &entries)) { chunk_information |= 1 << 13; // sPLT } if (png_get_sCAL(stream->png_ptr, stream->info_ptr, &unit, &width, &height)) { chunk_information |= 1 << 14; // sCAL } if (IDAT) { chunk_information |= 1 << 15; // IDAT } return chunk_information; }
/* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal) { BITMAP *bmp; PALETTE tmppal; png_uint_32 width, height, rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp, dest_bpp; int tRNS_to_alpha = FALSE; int number_passes, pass; ASSERT(png_ptr && info_ptr && rgb); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) png_set_expand(png_ptr); /* Adds a full alpha channel if there is transparency information * in a tRNS chunk. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); tRNS_to_alpha = TRUE; } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ if (_png_screen_gamma != 0.0) { screen_gamma = get_gamma(); if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Even if the user doesn't supply space for a palette, we want * one for the load process. */ if (!pal) pal = tmppal; /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red >> 2; /* 256 -> 64 */ pal[i].g = palette[i].green >> 2; pal[i].b = palette[i].blue >> 2; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } }
bool S9xLoadCrosshairFile (int idx, const char *filename) { if (idx < 1 || idx > 31) return (false); char *s = (char *) calloc(15 * 15 + 1, sizeof(char)); if (s == NULL) { fprintf(stderr, "S9xLoadCrosshairFile: malloc error while reading "); perror(filename); return (false); } FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "S9xLoadCrosshairFile: Couldn't open "); perror(filename); free(s); return (false); } size_t l = fread(s, 1, 8, fp); if (l != 8) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); free(s); fclose(fp); return (false); } #ifdef HAVE_LIBPNG png_structp png_ptr; png_infop info_ptr; if (!png_sig_cmp((png_byte *) s, 0, 8)) { png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { free(s); fclose(fp); return (false); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type != PNG_COLOR_TYPE_PALETTE) { fprintf(stderr, "S9xLoadCrosshairFile: Input PNG is not a palettized image!\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } if (bit_depth == 16) png_set_strip_16(png_ptr); if (width != 15 || height != 15) { fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 15x15 PNG\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_color *pngpal; png_byte *trans; int num_palette = 0, num_trans = 0; int transcol = -1, fgcol = -1, bgcol = -1; png_get_PLTE(png_ptr, info_ptr, &pngpal, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); if (num_palette != 3 || num_trans != 1) { fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 3-color PNG with 1 trasnparent color\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } for (int i = 0; i < 3; i++) { if (trans[0] == i) transcol = i; else if (pngpal[i].red == 0 && pngpal[i].green == 0 && pngpal[i].blue == 0) bgcol = i; else if (pngpal[i].red == 255 && pngpal[i].green == 255 && pngpal[i].blue == 255) fgcol = i; } if (transcol < 0 || fgcol < 0 || bgcol < 0) { fprintf(stderr, "S9xLoadCrosshairFile: PNG must have 3 colors: white (fg), black (bg), and transparent.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_byte *row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; for (int r = 0; r < 15 * 15; r += 15) { png_read_row(png_ptr, row_pointer, NULL); for (int i = 0; i < 15; i++) { if (row_pointer[i] == transcol) s[r + i] = ' '; else if (row_pointer[i] == fgcol) s[r + i] = '#'; else if (row_pointer[i] == bgcol) s[r + i] = '.'; else { fprintf(stderr, "S9xLoadCrosshairFile: WTF? This was supposed to be a 3-color PNG!\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } } } s[15 * 15] = 0; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); } else #endif { l = fread(s + 8, 1, 15 - 8, fp); if (l != 15 - 8) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); free(s); fclose(fp); return (false); } if (getc(fp) != '\n') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } for (int r = 1; r < 15; r++) { l = fread(s + r * 15, 1, 15, fp); if (l != 15) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } if (getc(fp) != '\n') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } } for (int i = 0; i < 15 * 15; i++) { if (s[i] != ' ' && s[i] != '#' && s[i] != '.') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } } } fclose(fp); if (crosshairs[idx] != NULL && crosshairs[idx][0] != '`') free((void *) crosshairs[idx]); crosshairs[idx] = s; return (true); }
gfx_t *gfx_load_png(char *filename) { gfx_t *gfx = 0; int i, x, y; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; png_uint_32 width, height, rowbytes; int bit_depth, color_type; png_byte *image_data = 0; png_bytep *row_pointers = 0; uint8_t sig[8]; FILE *infile; infile = fopen(filename, "rb"); if (!infile) { fprintf(stderr, "cant open `%s`\n", filename); return 0; } if (0) { fail: if (gfx) free(gfx); if (image_data) free(image_data); if (row_pointers) free(row_pointers); fclose(infile); return 0; } fread(sig, 1, 8, infile); if (!png_check_sig(sig, 8)) { fprintf(stderr, "bad signature for `%s`\n", filename); return 0; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "png_create_info_struct: out of memory for `%s`\n", filename); goto fail; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fprintf(stderr, "png_create_info_struct: out of memory for `%s`\n", filename); goto fail; } end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); goto fail; } // setjmp() must be called in every function that calls a PNG-reading libpng function if (setjmp(png_jmpbuf(png_ptr))) { jmpbuf_fail: png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto fail; } png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); // tell libpng that we already read the 8 signature bytes png_read_info(png_ptr, info_ptr); // read all PNG info up to image data png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); image_data = malloc(rowbytes * height * sizeof(png_byte)+15); if (!image_data) { fprintf(stderr, "load_png: could not allocate memory for PNG image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto jmpbuf_fail; } row_pointers = malloc(height * sizeof(png_bytep)); if (!row_pointers) { fprintf(stderr, "load_png: could not allocate memory for PNG row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto jmpbuf_fail; } for (y = 0; y < height; y++) { row_pointers[height - 1 - y] = image_data + y * rowbytes; } png_read_image(png_ptr, row_pointers); if (bit_depth != 8 && bit_depth != 16 && color_type != PNG_COLOR_TYPE_PALETTE) { fprintf(stderr, "load_png: unsupported bit_depth=%d\n", bit_depth); goto fail; } if (color_type == PNG_COLOR_TYPE_RGB) { //RGB gfx = new_gfx(width, height); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8(row[0], row[1], row[2])); row += 3; } } } else { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8(row[1], row[3], row[5])); row += 6; } } } } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { gfx = new_gfx(width, height); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8A8(row[0], row[1], row[2], 0xFF-row[3])); row += 4; } } } else { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, R8G8B8A8(row[1], row[3], row[5], 0xFF-row[7])); row += 8; } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE) { uint32_t cmap[GFX_CMAP_SIZE]; png_colorp palette; int num_palette; // palette size png_bytep trans; int num_trans; png_color_16p trans_values; gfx = new_gfx(width, height); if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) == 0) { fprintf(stderr, "load_png: couldn't retrieve palette\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto fail; } if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values) == 0) { num_trans = 0; } for (i = 0; i < num_palette; i++) { int a = i < num_trans ? 0xFF - trans[i] : 0; cmap[i] = R8G8B8A8(palette[i].red, palette[i].green, palette[i].blue, a); } gfx_set_cmap(gfx, cmap); if (bit_depth == 8) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { gfx_set(gfx, x, y, row[0]); row++; } } } else if (bit_depth == 4) { for (y = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; ) { png_byte c = row[0]; for (i = 4; i >=0 ; i-=4) { gfx_set(gfx, x, y, (c>>i)&0xF); if (++x == width) break; } row++; } } } else if (bit_depth == 2) {
bool create_image_png(image_struct* img, void* pData,int nDatalen,const char* name) { // length of bytes to check if it is a valid png file #define PNGSIGSIZE 8 bool bRet = false; png_byte header[PNGSIGSIZE] = {0}; png_structp png_ptr = 0; png_infop info_ptr = 0; do { // png header len is 8 bytes CC_BREAK_IF(nDatalen < PNGSIGSIZE); // check the data is png or not memcpy(header, pData, PNGSIGSIZE); CC_BREAK_IF(png_sig_cmp(header, 0, PNGSIGSIZE)); // init png_struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); CC_BREAK_IF(! png_ptr); // init png_info info_ptr = png_create_info_struct(png_ptr); CC_BREAK_IF(!info_ptr); #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA) CC_BREAK_IF(setjmp(png_jmpbuf(png_ptr))); #endif // set the read call back function tImageSource imageSource; imageSource.data = (colorbyte*)pData; imageSource.size = nDatalen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png header info // read png file info png_read_info(png_ptr, info_ptr); img->m_width = png_get_image_width(png_ptr, info_ptr); img->m_height = png_get_image_height(png_ptr, info_ptr); img->m_bits_component = png_get_bit_depth(png_ptr, info_ptr); img->m_bits_pixel = png_get_channels(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); //CCLOG("color type %u", color_type); printf("create_image_png %s w:%d h:%d type:%d bits:%d pixel:%d\n", name, img->m_width,img->m_height,color_type,img->m_bits_component,img->m_bits_pixel); // force palette images to be expanded to 24-bit RGB // it may include alpha channel if (color_type == PNG_COLOR_TYPE_PALETTE) { //png_set_palette_to_rgb(png_ptr); png_color *palette = NULL; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); img->set_palette_color((color_palette*)palette,num_palette); } // low-bit-depth grayscale images are to be expanded to 8 bits if (color_type == PNG_COLOR_TYPE_GRAY && img->m_bits_component < 8) { assert(0); //not support png_set_expand_gray_1_2_4_to_8(png_ptr); } // expand any tRNS chunk data into a full alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { //assert(0); //not support //png_set_tRNS_to_alpha(png_ptr); png_bytep trans_alpha; int num_trans; png_color_16p trans_color; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans,&trans_color)) { img->set_palette_alpha(trans_alpha,num_trans); } } // reduce images with 16-bit samples to 8 bits if (img->m_bits_component == 16) { assert(0); //not support png_set_strip_16(png_ptr); img->m_bits_component = 8; } // expand grayscale images to RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { assert(0); //not support png_set_gray_to_rgb(png_ptr); } // read png data // m_bits_component will always be 8 //img->m_bits_component = 8; png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes; rowbytes = png_get_rowbytes(png_ptr, info_ptr); assert(rowbytes * 8 / img->m_bits_component == img->get_line_pitch()); //printf("%d %d %d %d\n",rowbytes,m_height,rowbytes*m_height,get_buf_size()); //m_buffer = new colorbyte[rowbytes * m_height]; //assert(rowbytes * img->m_height == img->get_buf_size()); //img->m_buffer = new colorbyte[img->get_buf_size()]; //CC_BREAK_IF(!img->m_buffer); png_bytep* row_pointers = (png_bytep*)malloc( sizeof(png_bytep) * img->m_height ); colorbyte* buf = new colorbyte[rowbytes * img->m_height]; CC_BREAK_IF(!buf); for (int i = 0; i < img->m_height; ++i) { row_pointers[i] = buf + i*rowbytes; } png_read_image(png_ptr, row_pointers); if (img->m_bits_component == 8) { img->m_buffer = buf; } else { img->m_buffer = new colorbyte[img->get_buf_size()]; //memset(img->m_buffer,255,img->get_buf_size()); colorbyte* des = img->m_buffer; colorbyte* src = buf; int bits = img->m_bits_component; for (int i=0; i<img->get_buf_size(); ) { *des++ = get_bit(*src,i,bits); i++; if (i % (8/bits) == 0) src ++; } delete buf; } png_read_end(png_ptr, NULL); CC_SAFE_FREE(row_pointers); //png_uint_32 channel = rowbytes/img->m_width; //if (channel == 4) //{ // //img->m_alpha = true; // unsigned int *tmp = (unsigned int *)img->m_buffer; // for(unsigned short i = 0; i < img->m_height; i++) // { // for(unsigned int j = 0; j < rowbytes; j += 4) // { // *tmp++ = CC_RGB_PREMULTIPLY_ALPHA( row_pointers[i][j], row_pointers[i][j + 1], // row_pointers[i][j + 2], row_pointers[i][j + 3] ); // } // } // //img->m_premul_alpha = true; //} bRet = true; } while (0); if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return bRet; }
Error ImageLoaderPNG::_load_image(void *rf_up,png_rw_ptr p_func,Image *p_image) { png_structp png; png_infop info; //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,_png_error_function,_png_warn_function,(png_voidp)NULL, _png_malloc_fn,_png_free_fn ); ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY); info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png,NULL,NULL); ERR_PRINT("Out of Memory"); return ERR_OUT_OF_MEMORY; } if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png,NULL,NULL); ERR_PRINT("PNG Corrupted"); return ERR_FILE_CORRUPT; } png_set_read_fn(png,(void*)rf_up,p_func); png_uint_32 width, height; int depth, color; png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp //png_get_text(png,info,) /* printf("Image width:%i\n", width); printf("Image Height:%i\n", height); printf("Bit depth:%i\n", depth); printf("Color type:%i\n", color); */ if (depth<8) { //only bit dept 8 per channel is handled png_set_packing(png); }; if (depth > 8) { png_set_strip_16(png); png_read_update_info(png, info); } if (png_get_valid(png,info,PNG_INFO_tRNS)) { // png_set_expand_gray_1_2_4_to_8(png); png_set_tRNS_to_alpha(png); png_read_update_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); } int palette_colors = 0; int palette_components = 0; int components = 0; Image::Format fmt; switch(color) { case PNG_COLOR_TYPE_GRAY: { fmt=Image::FORMAT_GRAYSCALE; components=1; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; components=2; } break; case PNG_COLOR_TYPE_RGB: { fmt=Image::FORMAT_RGB; components=3; } break; case PNG_COLOR_TYPE_RGB_ALPHA: { fmt=Image::FORMAT_RGBA; components=4; } break; case PNG_COLOR_TYPE_PALETTE: { int ntrans = 0; png_get_tRNS(png, info, NULL, &ntrans, NULL); //printf("transparent colors %i\n", ntrans); fmt = ntrans > 0 ? Image::FORMAT_INDEXED_ALPHA : Image::FORMAT_INDEXED; palette_components = ntrans > 0 ? 4 : 3; components = 1; png_colorp colors; png_get_PLTE(png, info, &colors, &palette_colors); } break; default: { ERR_PRINT("INVALID PNG TYPE"); png_destroy_read_struct(&png, &info, NULL); return ERR_UNAVAILABLE; } break; } //int rowsize = png_get_rowbytes(png, info); int rowsize = components * width; DVector<uint8_t> dstbuff; dstbuff.resize( rowsize * height + palette_components * 256 ); // alloc the entire palette? - yes always DVector<uint8_t>::Write dstbuff_write = dstbuff.write(); uint8_t* data = dstbuff_write.ptr(); uint8_t **row_p = memnew_arr( uint8_t*, height ); for (unsigned int i = 0; i < height; i++) { row_p[i] = &data[components*width*i]; } png_read_image(png, (png_bytep*)row_p); if (palette_colors) { uint8_t *r_pal = &data[components*width*height]; // end of the array png_colorp colors; int num; png_get_PLTE(png, info, &colors, &num); int ofs = 0; for (int i=0; i < palette_colors; i++) { r_pal[ofs + 0] = colors[i].red; r_pal[ofs + 1] = colors[i].green; r_pal[ofs + 2] = colors[i].blue; if (palette_components == 4) { r_pal[ofs + 3] = 255; }; ofs += palette_components; }; if (fmt == Image::FORMAT_INDEXED_ALPHA) { png_color_16p alphas; png_bytep alpha_idx; int count; png_get_tRNS(png, info, &alpha_idx, &count, &alphas); for (int i=0; i<count; i++) { //printf("%i: loading alpha fron transparent color %i, values %i, %i, %i, %i, %i\n", i, (int)alpha_idx[i], (int)alphas[i].index, (int)alphas[i].red, (int)alphas[i].green, (int)alphas[i].blue, (int)alphas[i].gray); //r_pal[alpha_idx[i]] = alphas[i].gray >> 8; r_pal[i*4+3] = alpha_idx[i]; }; }; }; memdelete_arr( row_p ); p_image->create( width, height, 0,fmt, dstbuff ); png_destroy_read_struct(&png, &info, NULL ); return OK; }
static int readpng(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight) { int i, j, cw, ch; png_colorp png_pal_ptr = 0; int png_pal_num = 0; int pb = PAL_BYTES; cw = res[0] > maxwidth ? maxwidth : res[0]; ch = res[1] > maxheight ? maxheight : res[1]; if(buf) { for(i = 0; i < ch; i++) { memcpy(buf + (maxwidth * i), row_pointers[i], cw); } } if(pal) { if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) { // set palette for grayscale images for(i = 0; i < 256; i++) { pal[i * 3] = pal[i * 3 + 1] = pal[i * 3 + 2] = i; } return 1; } else if(png_get_PLTE(png_ptr, info_ptr, &png_pal_ptr, &png_pal_num) != PNG_INFO_PLTE || png_pal_ptr == NULL) { return 0; } png_pal_ptr[0].red = png_pal_ptr[0].green = png_pal_ptr[0].blue = 0; if(pb == 512) // 16bit 565 { for(i = 0, j = 0; i < 512 && j < png_pal_num; i += 2, j++) { *(unsigned short *)(pal + i) = colour16(png_pal_ptr[j].red, png_pal_ptr[j].green, png_pal_ptr[j].blue); } } else if(pb == 768) // 24bit { for(i = 0; i < png_pal_num; i++) { pal[i * 3] = png_pal_ptr[i].red; pal[i * 3 + 1] = png_pal_ptr[i].green; pal[i * 3 + 2] = png_pal_ptr[i].blue; } } else if(pb == 1024) // 32bit { for(i = 0, j = 0; i < 1024 && j < png_pal_num; i += 4, j++) { *(unsigned *)(pal + i) = colour32(png_pal_ptr[j].red, png_pal_ptr[j].green, png_pal_ptr[j].blue); } } } return 1; }
/*! * pixReadStreamPng() * * Input: stream * Return: pix, or null on error * * Notes: * (1) If called from pixReadStream(), the stream is positioned * at the beginning of the file. * (2) To do sequential reads of png format images from a stream, * use pixReadStreamPng() */ PIX * pixReadStreamPng(FILE *fp) { l_uint8 rval, gval, bval; l_int32 i, j, k; l_int32 wpl, d, spp, cindex; l_uint32 png_transforms; l_uint32 *data, *line, *ppixel; int num_palette, num_text; png_byte bit_depth, color_type, channels; png_uint_32 w, h, rowbytes; png_uint_32 xres, yres; png_bytep rowptr; png_bytep *row_pointers; png_structp png_ptr; png_infop info_ptr, end_info; png_colorp palette; png_textp text_ptr; /* ptr to text_chunk */ PIX *pix; PIXCMAP *cmap; PROCNAME("pixReadStreamPng"); if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); pix = NULL; /* Allocate the 3 data structures */ if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL)) == NULL) return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL); if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL); } if ((end_info = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return (PIX *)ERROR_PTR("end_info not made", procName, NULL); } /* Set up png setjmp error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("internal png error", procName, NULL); } png_init_io(png_ptr, fp); /* ---------------------------------------------------------- * * Set the transforms flags. Whatever happens here, * NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO. * ---------------------------------------------------------- */ /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */ if (var_PNG_STRIP_16_TO_8 == 1) /* our default */ png_transforms = PNG_TRANSFORM_STRIP_16; else png_transforms = PNG_TRANSFORM_IDENTITY; /* To remove alpha channel, use PNG_TRANSFORM_STRIP_ALPHA */ if (var_PNG_STRIP_ALPHA == 1) /* our default */ png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; /* Read it */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); w = png_get_image_width(png_ptr, info_ptr); h = png_get_image_height(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); spp = channels; if (spp == 1) d = bit_depth; else if (spp == 2) { d = 2 * bit_depth; L_WARNING("there shouldn't be 2 spp!", procName); } else /* spp == 3 (rgb), spp == 4 (rgba) */ d = 4 * bit_depth; /* Remove if/when this is implemented for all bit_depths */ if (spp == 3 && bit_depth != 8) { fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("not implemented for this depth", procName, NULL); } if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_MASK_PALETTE) { /* generate a colormap */ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); cmap = pixcmapCreate(d); /* spp == 1 */ for (cindex = 0; cindex < num_palette; cindex++) { rval = palette[cindex].red; gval = palette[cindex].green; bval = palette[cindex].blue; pixcmapAddColor(cmap, rval, gval, bval); } } else cmap = NULL; if ((pix = pixCreate(w, h, d)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("pix not made", procName, NULL); } wpl = pixGetWpl(pix); data = pixGetData(pix); pixSetColormap(pix, cmap); if (spp == 1) { /* copy straight from buffer to pix */ for (i = 0; i < h; i++) { line = data + i * wpl; rowptr = row_pointers[i]; for (j = 0; j < rowbytes; j++) { SET_DATA_BYTE(line, j, rowptr[j]); } } } else { /* spp == 3 or spp == 4 */ for (i = 0; i < h; i++) { ppixel = data + i * wpl; rowptr = row_pointers[i]; for (j = k = 0; j < w; j++) { SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]); if (spp == 4) SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]); ppixel++; } } } #if DEBUG if (cmap) { for (i = 0; i < 16; i++) { fprintf(stderr, "[%d] = %d\n", i, ((l_uint8 *)(cmap->array))[i]); } } #endif /* DEBUG */ /* If there is no colormap, PNG defines black = 0 and * white = 1 by default for binary monochrome. Therefore, * since we use the opposite definition, we must invert * the image colors in either of these cases: * (i) there is no colormap (default) * (ii) there is a colormap which defines black to * be 0 and white to be 1. * We cannot use the PNG_TRANSFORM_INVERT_MONO flag * because that flag (since version 1.0.9) inverts 8 bpp * grayscale as well, which we don't want to do. * (It also doesn't work if there is a colormap.) * If there is a colormap that defines black = 1 and * white = 0, we don't need to do anything. * * How do we check the polarity of the colormap? * The colormap determines the values of black and * white pixels in the following way: * if black = 1 (255), white = 0 * 255, 255, 255, 0, 0, 0, 0, 0, 0 * if black = 0, white = 1 (255) * 0, 0, 0, 0, 255, 255, 255, 0 * So we test the first byte to see if it is 0; * if so, invert the colors. * * If there is a colormap, after inverting the pixels it is * necessary to destroy the colormap. Otherwise, if someone were * to call pixRemoveColormap(), this would cause the pixel * values to be inverted again! */ if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) { /* fprintf(stderr, "Inverting binary data on png read\n"); */ pixInvert(pix, pix); pixDestroyColormap(pix); } xres = png_get_x_pixels_per_meter(png_ptr, info_ptr); yres = png_get_y_pixels_per_meter(png_ptr, info_ptr); pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */ pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */ /* Get the text if there is any */ png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); if (num_text && text_ptr) pixSetText(pix, text_ptr->text); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return pix; }
/* TODO: I wonder why this function ALWAYS returns 0 */ int loadPNG(ePtr<gPixmap> &result, const char *filename, int accel) { if (pixmapFromTable(result, filename) == 0) return 0; CFile fp(filename, "rb"); if (!fp) { eDebug("[ePNG] couldn't open %s", filename ); return 0; } { uint8_t header[8]; if (!fread(header, 1, 8, fp)) { eDebug("[ePNG] failed to get png header"); return 0; } if (png_sig_cmp(header, 0, 8)) { eDebug("[ePNG] header size mismatch"); return 0; } } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { eDebug("[ePNG] failed to create read struct"); return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { eDebug("[ePNG] failed to create info struct"); png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { eDebug("[ePNG] failed to create end info struct"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { eDebug("[ePNG] png setjump failed or activated"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); result = 0; return 0; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth; int color_type; int interlace_type; int channels; int trns; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, 0, 0); channels = png_get_channels(png_ptr, info_ptr); trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); //eDebug("[ePNG] %s: before %dx%dx%dbpcx%dchan coltyp=%d", filename, (int)width, (int)height, bit_depth, channels, color_type); /* * gPixmaps use 8 bits per channel. rgb pixmaps are stored as abgr. * So convert 1,2 and 4 bpc to 8bpc images that enigma can blit * so add 'empty' alpha channel * Expand G+tRNS to GA, RGB+tRNS to RGBA */ if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing (png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && trns) png_set_tRNS_to_alpha(png_ptr); if ((color_type == PNG_COLOR_TYPE_GRAY && trns) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); } if (color_type == PNG_COLOR_TYPE_RGB) { if (trns) png_set_tRNS_to_alpha(png_ptr); else png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // Update the info structures after the transformations take effect if (interlace_type != PNG_INTERLACE_NONE) png_set_interlace_handling(png_ptr); // needed before read_update_info() png_read_update_info (png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); channels = png_get_channels(png_ptr, info_ptr); result = new gPixmap(width, height, bit_depth * channels, pixmapDisposed, accel); gUnmanagedSurface *surface = result->surface; png_bytep *rowptr = new png_bytep[height]; for (unsigned int i = 0; i < height; i++) rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride; png_read_image(png_ptr, rowptr); delete [] rowptr; int num_palette = -1, num_trans = -1; if (color_type == PNG_COLOR_TYPE_PALETTE) { if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_color *palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette) surface->clut.data = new gRGB[num_palette]; else surface->clut.data = 0; surface->clut.colors = num_palette; for (int i = 0; i < num_palette; i++) { surface->clut.data[i].a = 0; surface->clut.data[i].r = palette[i].red; surface->clut.data[i].g = palette[i].green; surface->clut.data[i].b = palette[i].blue; } if (trns) { png_byte *trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0); for (int i = 0; i < num_trans; i++) surface->clut.data[i].a = 255 - trans[i]; for (int i = num_trans; i < num_palette; i++) surface->clut.data[i].a = 0; } } else { surface->clut.data = 0; surface->clut.colors = 0; } surface->clut.start = 0; } pixmapToTable(result, filename); //eDebug("[ePNG] %s: after %dx%dx%dbpcx%dchan coltyp=%d cols=%d trans=%d", filename, (int)width, (int)height, bit_depth, channels, color_type, num_palette, num_trans); png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return 0; }
int APIENTRY pngLoadRawF(FILE *fp, pngRawInfo *pinfo) { unsigned char header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep data; png_bytep *row_p; double fileGamma; png_uint_32 width, height; int depth, color; png_uint_32 i; if (pinfo == NULL) return 0; if (fread(header, 1, 8, fp) != 8 || !png_check_sig(header, 8)) return 0; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); endinfo = png_create_info_struct(png); /* DH: added following lines */ if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &info, &endinfo); return 0; } /* ~DH */ png_init_io(png, fp); png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); pinfo->Width = width; pinfo->Height = height; pinfo->Depth = depth; /*--GAMMA--*/ checkForGammaEnv(); if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); data = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i]; else row_p[i] = &data[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); if (color == PNG_COLOR_TYPE_PALETTE) { int cols; png_get_PLTE(png, info, (png_colorp *) &pinfo->Palette, &cols); } else { pinfo->Palette = NULL; } if (color&PNG_COLOR_MASK_ALPHA) { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY_ALPHA) pinfo->Components = 2; else pinfo->Components = 4; pinfo->Alpha = 8; } else { if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY) pinfo->Components = 1; else pinfo->Components = 3; pinfo->Alpha = 0; } pinfo->Data = data; png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); return 1; }
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, SkBitmap::Config prefConfig, Mode mode) { // SkAutoTrace apr("SkPNGImageDecoder::onDecode"); /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL); // png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { return false; } /* Allocate/initialize the memory for image information. */ png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return false; } PNGAutoClean autoClean(png_ptr, info_ptr); /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { return false; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ /* If we have already read some of the signature */ // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); // hookup our peeker so we can see any user-chunks the caller may be interested in png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); if (this->getPeeker()) { png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); } /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); SkBitmap::Config config; bool hasAlpha = false; bool doDither = this->getDitherImage(); // check for sBIT chunk data, in case we should disable dithering because // our data is not truely 8bits per component if (doDither) { #if 0 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, info_ptr->sig_bit.green, info_ptr->sig_bit.blue, info_ptr->sig_bit.alpha); #endif // 0 seems to indicate no information available if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { doDither = false; } } if (color_type == PNG_COLOR_TYPE_PALETTE) { config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha } else { png_color_16p transColor; png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || PNG_COLOR_TYPE_RGB_ALPHA == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { hasAlpha = true; config = SkBitmap::kARGB_8888_Config; } else { // we get to choose the config config = prefConfig; if (config == SkBitmap::kNo_Config) { config = SkImageDecoder::GetDeviceConfig(); } if (config != SkBitmap::kRGB_565_Config && config != SkBitmap::kARGB_4444_Config) { config = SkBitmap::kARGB_8888_Config; } } } if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { return false; } const int sampleSize = this->getSampleSize(); SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } // from here down we are concerned with colortables and pixels /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (bit_depth == 16) { png_set_strip_16(png_ptr); } /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (bit_depth < 8) { png_set_packing(png_ptr); } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we // draw lots faster if we can flag the bitmap has being opaque bool reallyHasAlpha = false; SkColorTable* colorTable = NULL; if (color_type == PNG_COLOR_TYPE_PALETTE) { int num_palette; png_colorp palette; png_bytep trans; int num_trans; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); /* BUGGY IMAGE WORKAROUND We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count which is a problem since we use the byte as an index. To work around this we grow the colortable by 1 (if its < 256) and duplicate the last color into that slot. */ int colorCount = num_palette + (num_palette < 256); colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); SkPMColor* colorPtr = colorTable->lockColors(); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); hasAlpha = (num_trans > 0); } else { num_trans = 0; colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); } // check for bad images that might make us crash if (num_trans > num_palette) { num_trans = num_palette; } int index = 0; int transLessThanFF = 0; for (; index < num_trans; index++) { transLessThanFF |= (int)*trans - 0xFF; *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); palette++; } reallyHasAlpha |= (transLessThanFF < 0); for (; index < num_palette; index++) { *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); palette++; } // see BUGGY IMAGE WORKAROUND comment above if (num_palette < 256) { *colorPtr = colorPtr[-1]; } colorTable->unlockColors(true); } SkAutoUnref aur(colorTable); if (!this->allocPixelRef(decodedBitmap, colorTable)) { delete colorTable; return false; } SkAutoLockPixels alp(*decodedBitmap); /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // ; // png_set_swap_alpha(png_ptr); /* swap bytes of 16 bit files to least significant byte first */ // png_set_swap(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ const int number_passes = interlace_type != PNG_INTERLACE_NONE ? png_set_interlace_handling(png_ptr) : 1; /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (ie you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { for (int i = 0; i < number_passes; i++) { for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = decodedBitmap->getAddr8(0, y); png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); } } } else { SkScaledBitmapSampler::SrcConfig sc; int srcBytesPerPixel = 4; if (SkBitmap::kIndex8_Config == config) { sc = SkScaledBitmapSampler::kIndex; srcBytesPerPixel = 1; } else if (hasAlpha) { sc = SkScaledBitmapSampler::kRGBA; } else { sc = SkScaledBitmapSampler::kRGBX; } SkAutoMalloc storage(origWidth * srcBytesPerPixel); const int height = decodedBitmap->height(); for (int i = 0; i < number_passes; i++) { if (!sampler.begin(decodedBitmap, sc, doDither)) { return false; } uint8_t* srcRow = (uint8_t*)storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); reallyHasAlpha |= sampler.next(srcRow); if (y < height - 1) { skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); } } // skip the rest of the rows (if any) png_uint_32 read = (height - 1) * sampler.srcDY() + sampler.srcY0() + 1; SkASSERT(read <= origHeight); skip_src_rows(png_ptr, srcRow, origHeight - read); } if (hasAlpha && !reallyHasAlpha) { SkDEBUGF(("Image doesn't really have alpha [%d %d]\n", origWidth, origHeight)); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); decodedBitmap->setIsOpaque(!reallyHasAlpha); return true; }
int main(int argc, char **argv) { char* outfile = NULL; save_mode mode = RAW; unsigned split_w = 0; unsigned split_h = 0; int opt; while((opt=getopt(argc, argv, "brpns:o:h?")) != -1) { switch(opt) { case 'b': mode = BINARY; break; case 'n': mode = PALETTE_NO_OUTPUT; break; case 'p': mode = PALETTE; break; case 'r': mode = RGB; break; case 's': { unsigned pos; if(sscanf(optarg, "%ux%u%n", &split_w, &split_h, &pos)!=2 || pos != strlen(optarg)) { usage(); exit(1); } } break; case 'o': outfile = optarg; break; case 'h': case '?': usage(); exit(1); } } char** inputfiles = argv + optind; unsigned inputcount = argc - optind; if (!inputcount) { usage(); exit(1); } for (unsigned input_nr = 0; input_nr < inputcount; input_nr++) { FILE *f = fopen(inputfiles[input_nr], "rb"); if (!f) { fprintf(stderr, "Could not open file %s for reading\n", inputfiles[input_nr]); continue; } char *out = outfile; if (!out) { out = (char*)malloc(strlen(inputfiles[input_nr])+3); sprintf(out, "%s.h", inputfiles[input_nr]); } FILE *outstream = fopen(out, "w"); if (!outstream) { fprintf(stderr, "Could not open file %s for writing\n", out); continue; } char *file_basename = basename(inputfiles[input_nr]); for (unsigned i = 0; i < strlen(file_basename); i++) { if (file_basename[i] >= 'a' && file_basename[i] <= 'z') { file_basename[i] = file_basename[i] + 'A' - 'a'; } else if (file_basename[i] >= 'A' && file_basename[i] <= 'Z') { } else { file_basename[i] = '_'; } } char *data_array_name = (char*)malloc(strlen(file_basename)+6); sprintf(data_array_name, "%s_DATA", file_basename); char *plte_array_name = (char*)malloc(strlen(file_basename)+6); sprintf(plte_array_name, "%s_PLTE", file_basename); unsigned char header[8]; fread(header, 1, 8, f); if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "%s is not a png file", inputfiles[input_nr]); continue; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "png_create_read_struct failed"); continue; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr, "png_create_info_struct failed"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); continue; } if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "Error during init_io"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); continue; } png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); unsigned width = png_get_image_width(png_ptr, info_ptr); unsigned height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (mode == PALETTE || mode == PALETTE_NO_OUTPUT) { // does the user want palette output? if ((color_type & PNG_COLOR_MASK_PALETTE) == 0 && (color_type & PNG_COLOR_MASK_COLOR)) { //the image must have a palette or be grayscale fprintf(stderr, "%s is not a palette or grayscale image\n", inputfiles[input_nr]); continue; } } png_set_interlace_handling(png_ptr); // Reduce to 8 bits png_set_strip_16(png_ptr); png_set_strip_alpha(png_ptr); // Unpack 1, 2, 4 bits into 8 png_set_packing(png_ptr); if (mode == RGB) { png_set_palette_to_rgb(png_ptr); } // Done setting read flags png_read_update_info(png_ptr, info_ptr); png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); for (unsigned y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, info_ptr); if (mode == PALETTE) { if (color_type & PNG_COLOR_MASK_COLOR) { // image is actually paletted int plte_length; png_colorp plte_colors; png_get_PLTE(png_ptr, info_ptr, &plte_colors, &plte_length); fprintf(outstream, "uint32_t %s[%d] = {\n", plte_array_name, plte_length); for (int i = 0; i < plte_length; i++) { uint32_t color = plte_colors[i].red << 16 | plte_colors[i].green << 8 | plte_colors[i].blue; fprintf(outstream, "0x%06lX, ", (unsigned long)color); } fprintf(outstream, "\n};\n\n"); } else { // create a default grayscale palette int plte_length = 1 << bit_depth; fprintf(outstream, "uint32_t %s[%d] = {\n", plte_array_name, plte_length); for (int i = 0; i < plte_length; i++) { printf("%d\n", i); int current_bits = i; uint32_t color = 0; int target_bits = 3 * 8; for (int bit = 0; bit < target_bits; bit += bit_depth) { color |= current_bits; current_bits <<= bit_depth; } fprintf(outstream, "0x%06lX, ", (unsigned long)color); } fprintf(outstream, "};\n\n"); } } unsigned tile_h = split_h ? split_h : height; unsigned tile_w = split_w ? split_w : width; unsigned byte_per_pixel = png_get_rowbytes(png_ptr, info_ptr) / width; unsigned long pixel_count = width * height; fprintf(outstream, "uint%d_t %s[%lu] = {\n", mode == RGB ? 32 : 8, data_array_name, mode == BINARY ? pixel_count / 8 : pixel_count); for (unsigned tile_y = 0; tile_y + tile_h <= height; tile_y += tile_h) { for (unsigned tile_x = 0; tile_x + tile_w <= width; tile_x += tile_w) { fprintf(outstream, "// Tile (%d, %d)\n", tile_x / tile_w, tile_y / tile_h); switch(mode) { case BINARY: for (unsigned y = tile_y; y < tile_y + tile_h; y++) { png_byte* row = row_pointers[y]; for (unsigned x0 = tile_x; x0 < tile_x + tile_w; x0 += 8) { uint8_t current_bit = 1; uint8_t total = 0; for (unsigned x = x0; x < x0 + 8 && x < tile_x + tile_w; x++, current_bit <<= 1) { if (row[byte_per_pixel * x]) { total |= current_bit; } } fprintf(outstream, "0x%02X, ", total); } fprintf(outstream, "\n"); } break; case PALETTE: case PALETTE_NO_OUTPUT: for (unsigned y = tile_y; y < tile_y + tile_h; y++) { png_byte* row = row_pointers[y]; for (unsigned x = tile_x; x < tile_x + tile_w; x++) { fprintf(outstream, "%d, ", row[byte_per_pixel * x]); } fprintf(outstream, "\n"); } break; case RGB: case RAW: default: for (unsigned y = tile_y; y < tile_y + tile_h; y++) { png_byte* row = row_pointers[y]; for (unsigned x = tile_x; x < tile_x + tile_w; x++) { fprintf(outstream, "0x"); for (unsigned i = 0; i < byte_per_pixel; i++) { fprintf(outstream, "%02X", row[byte_per_pixel * x + i]); } fprintf(outstream, ", "); } fprintf(outstream, "\n"); } break; } } } fprintf(outstream, "};\n\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(f); } }
// This function uses wxPNGImageData to store some of its "local" variables in // order to avoid clobbering these variables by longjmp(): having them inside // the stack frame of the caller prevents this from happening. It also // "returns" its result via wxPNGImageData: use its "ok" field to check // whether loading succeeded or failed. void wxPNGImageData::DoLoadPNGFile(wxImage* image, wxPNGInfoStruct& wxinfo) { png_uint_32 width, height = 0; int bit_depth, color_type, interlace_type; image->Destroy(); png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, wx_PNG_error, wx_PNG_warning ); if (!png_ptr) return; // NB: please see the comment near wxPNGInfoStruct declaration for // explanation why this line is mandatory png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); info_ptr = png_create_info_struct( png_ptr ); if (!info_ptr) return; if (setjmp(wxinfo.jmpbuf)) return; png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr ); // Fix for Bug [ 439207 ] Monochrome PNG images come up black if (bit_depth < 8) png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_packing( png_ptr ); if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr ); png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); if (!image->IsOk()) return; if ( !Alloc(width, height) ) return; png_read_image( png_ptr, lines ); png_read_end( png_ptr, info_ptr ); #if wxUSE_PALETTE if (color_type == PNG_COLOR_TYPE_PALETTE) { png_colorp palette = NULL; int numPalette = 0; (void) png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); unsigned char* r = new unsigned char[numPalette]; unsigned char* g = new unsigned char[numPalette]; unsigned char* b = new unsigned char[numPalette]; for (int j = 0; j < numPalette; j++) { r[j] = palette[j].red; g[j] = palette[j].green; b[j] = palette[j].blue; } image->SetPalette(wxPalette(numPalette, r, g, b)); delete[] r; delete[] g; delete[] b; } #endif // wxUSE_PALETTE // set the image resolution if it's available png_uint_32 resX, resY; int unitType; if (png_get_pHYs(png_ptr, info_ptr, &resX, &resY, &unitType) == PNG_INFO_pHYs) { wxImageResolution res = wxIMAGE_RESOLUTION_CM; switch (unitType) { default: wxLogWarning(_("Unknown PNG resolution unit %d"), unitType); wxFALLTHROUGH; case PNG_RESOLUTION_UNKNOWN: image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, resX); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, resY); res = wxIMAGE_RESOLUTION_NONE; break; case PNG_RESOLUTION_METER: /* Convert meters to centimeters. Use a string to not lose precision (converting to cm and then to inch would result in integer rounding error). If an app wants an int, GetOptionInt will convert and round down for them. */ image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, wxString::FromCDouble((double) resX / 100.0, 2)); image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, wxString::FromCDouble((double) resY / 100.0, 2)); break; } image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, res); } // loaded successfully, now init wxImage with this data CopyDataFromPNG(image, lines, width, height, color_type); // This will indicate to the caller that loading succeeded. ok = true; }