diff --git a/GRRLIB/GRRLIB/GRRLIB_fileIO.c b/GRRLIB/GRRLIB/GRRLIB_fileIO.c index b478e31..6c63155 100644 --- a/GRRLIB/GRRLIB/GRRLIB_fileIO.c +++ b/GRRLIB/GRRLIB/GRRLIB_fileIO.c @@ -94,9 +94,9 @@ bool GRRLIB_ScrShot(const char* filename) { int ret = -1; if ( (pngContext = PNGU_SelectImageFromDevice(filename)) ) { - ret = PNGU_EncodeFromYCbYCr( pngContext, - rmode->fbWidth, rmode->efbHeight, - xfb[fb], 0 ); + ret = PNGU_EncodeFromEFB( pngContext, + rmode->fbWidth, rmode->efbHeight, + 0 ); PNGU_ReleaseImageContext(pngContext); } return !ret; diff --git a/GRRLIB/GRRLIB/GRRLIB_snapshot.c b/GRRLIB/GRRLIB/GRRLIB_snapshot.c index b2ec55c..0665e6f 100644 --- a/GRRLIB/GRRLIB/GRRLIB_snapshot.c +++ b/GRRLIB/GRRLIB/GRRLIB_snapshot.c @@ -43,8 +43,8 @@ void GRRLIB_Screen2Texture (int posx, int posy, GRRLIB_texImg *tex, bool clear) * Start GX compositing process. * @see GRRLIB_CompoEnd */ -void GRRLIB_CompoStart (void){ - GX_SetPixelFmt(GX_PF_RGBA6_Z24,GX_ZC_LINEAR); +void GRRLIB_CompoStart (void) { + GX_SetPixelFmt(GX_PF_RGBA6_Z24, GX_ZC_LINEAR); GX_PokeAlphaRead(GX_READ_NONE); } @@ -56,7 +56,7 @@ void GRRLIB_CompoStart (void){ * @param posy top left corner of the grabbed part. * @param tex A pointer to a texture representing the screen or NULL if an error occurs. */ -void GRRLIB_CompoEnd(int posx, int posy, GRRLIB_texImg *tex){ +void GRRLIB_CompoEnd(int posx, int posy, GRRLIB_texImg *tex) { GRRLIB_Screen2Texture(posx, posy, tex, FALSE); GX_SetTexCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight); diff --git a/GRRLIB/lib/pngu/pngu.c b/GRRLIB/lib/pngu/pngu.c index b1d553e..f2ca331 100644 --- a/GRRLIB/lib/pngu/pngu.c +++ b/GRRLIB/lib/pngu/pngu.c @@ -682,6 +682,166 @@ int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu return PNGU_OK; } +// Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui) +int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + png_uint_32 rowbytes; + PNGU_u32 y; + + // Erase from the context any readed info + pngu_free_info (ctx); + ctx->propRead = 0; + + // Check if the user has selected a file to write the image + if (ctx->source == PNGU_SOURCE_BUFFER); + + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Open file + if (!(ctx->fd = fopen (ctx->filename, "wb"))) + return PNGU_CANT_OPEN_FILE; + } + + else + return PNGU_NO_FILE_SELECTED; + + // Allocation of libpng structs + ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!(ctx->png_ptr)) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->info_ptr = png_create_info_struct (ctx->png_ptr); + if (!(ctx->info_ptr)) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + if (ctx->source == PNGU_SOURCE_BUFFER) + { + // Installation of our custom data writer function + ctx->cursor = 0; + png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); + } + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Default data writer uses function fwrite, so it needs to use our FILE* + png_init_io (ctx->png_ptr, ctx->fd); + } + + // Setup output file properties + png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // Allocate memory to store the image in RGB format + rowbytes = width * 3; + if (rowbytes % 4) + rowbytes = ((rowbytes / 4) + 1) * 4; // Add extra padding so each row starts in a 4 byte boundary + + ctx->img_data = malloc(rowbytes * height); + memset(ctx->img_data, 0, rowbytes * height); + + if (!ctx->img_data) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->row_pointers = malloc (sizeof (png_bytep) * height); + memset(ctx->row_pointers, 0, sizeof (png_bytep) * height); + + if (!ctx->row_pointers) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + for (y = 0; y < height; y++) + { + ctx->row_pointers[y] = buffer + (y * rowbytes); + } + + // Tell libpng where is our image data + png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); + + // Write file header and image data + png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // Tell libpng we have no more data to write + png_write_end (ctx->png_ptr, (png_infop) NULL); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + + // Success + return ctx->cursor; +} + +// Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui) +int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + int x,y,res; + unsigned char * ptr = (unsigned char*)buffer; + unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); + memset(tmpbuffer, 0, width*height*3); + png_uint_32 offset; + + for(y=0; y < height; y++) + { + for(x=0; x < width; x++) + { + offset = (((y >> 2)<<4)*width) + ((x >> 2)<<6) + (((y%4 << 2) + x%4 ) << 1); + + tmpbuffer[y*640*3+x*3] = ptr[offset+1]; // R + tmpbuffer[y*640*3+x*3+1] = ptr[offset+32]; // G + tmpbuffer[y*640*3+x*3+2] = ptr[offset+33]; // B + } + } + + res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); + free(tmpbuffer); + return res; +} + +// Coded by Crayon for GRRLIB (http://code.google.com/p/grrlib) +int PNGU_EncodeFromEFB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stride) +{ + int x,y,res; + unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); + memset(tmpbuffer, 0, width*height*3); + PNGU_u32 ARGBColor; + + for(y=0; y < height; y++) + { + for(x=0; x < width; x++) + { + GX_PeekARGB(x, y, &ARGBColor); + + tmpbuffer[y*640*3+x*3] = (((ARGBColor) >>16) & 0xFF); // R + tmpbuffer[y*640*3+x*3+1] = (((ARGBColor) >> 8) & 0xFF); // G + tmpbuffer[y*640*3+x*3+2] = ( (ARGBColor) & 0xFF); // B + } + } + + res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); + free(tmpbuffer); + return res; +} + int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) { diff --git a/GRRLIB/lib/pngu/pngu.h b/GRRLIB/lib/pngu/pngu.h index 12c3ad4..e1e20b6 100644 --- a/GRRLIB/lib/pngu/pngu.h +++ b/GRRLIB/lib/pngu/pngu.h @@ -157,6 +157,10 @@ int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu // specify context, image dimensions, destination address and stride in pixels (stride = buffer width - image width). int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); +int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); +int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); +int PNGU_EncodeFromEFB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stride); + // Macro for encoding an image stored into an YCbYCr buffer at given coordinates. #define PNGU_ENCODE_TO_COORDS_YCbYCr(ctx,coordX,coordY,imgWidth,imgHeight,bufferWidth,bufferHeight,buffer) \ \