Created
December 6, 2013 08:50
-
-
Save xiaolu/7820623 to your computer and use it in GitHub Desktop.
gsnap static
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LOCAL_PATH:= $(call my-dir) | |
include $(CLEAR_VARS) | |
LOCAL_ARM_MODE := arm | |
LOCAL_SRC_FILES := \ | |
gsnap.c | |
LOCAL_C_INCLUDES += \ | |
external/jpeg \ | |
external/libpng \ | |
external/zlib | |
LOCAL_STATIC_LIBRARIES := libjpeg_static libpng libz libc libcutils | |
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES | |
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities | |
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities | |
LOCAL_MODULE_TAGS := eng | |
LOCAL_MODULE := gsnap | |
LOCAL_FORCE_STATIC_EXECUTABLE := true | |
include $(BUILD_EXECUTABLE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: gsnap.c | |
* Author: Li XianJing <[email protected]> | |
* Brief: snap the linux mobile device screen. | |
* | |
* Copyright (c) 2009 Li XianJing <[email protected]> | |
* | |
* Licensed under the Academic Free License version 2.1 | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
*/ | |
/* | |
* History: | |
* ================================================================ | |
* 2009-08-20 Li XianJing <[email protected]> created | |
* 2011-02-28 Li XianJing <[email protected]> suppport RGB888 framebuffer. | |
* 2011-04-09 Li XianJing <[email protected]> merge figofuture's png output. | |
* ref: http://blog.chinaunix.net/space.php?uid=15059847&do=blog&cuid=2040565 | |
* | |
*/ | |
#include <png.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <jpeglib.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <linux/fb.h> | |
#include <linux/kd.h> | |
struct _FBInfo; | |
typedef struct _FBInfo FBInfo; | |
typedef int (*UnpackPixel)(FBInfo* fb, unsigned char* pixel, | |
unsigned char* r, unsigned char* g, unsigned char* b); | |
struct _FBInfo | |
{ | |
int fd; | |
UnpackPixel unpack; | |
unsigned char *bits; | |
struct fb_fix_screeninfo fi; | |
struct fb_var_screeninfo vi; | |
}; | |
#define fb_width(fb) ((fb)->vi.xres) | |
#define fb_height(fb) ((fb)->vi.yres) | |
#define fb_bpp(fb) ((fb)->vi.bits_per_pixel>>3) | |
//#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * fb_bpp(fb)) | |
#define fb_size(fb) ((fb)->fi.smem_len) | |
static int fb_unpack_rgb565(FBInfo* fb, unsigned char* pixel, | |
unsigned char* r, unsigned char* g, unsigned char* b) | |
{ | |
unsigned short color = *(unsigned short*)pixel; | |
*r = ((color >> 11) & 0xff) << 3; | |
*g = ((color >> 5) & 0xff) << 2; | |
*b = (color & 0xff )<< 3; | |
return 0; | |
} | |
static int fb_unpack_rgb24(FBInfo* fb, unsigned char* pixel, | |
unsigned char* r, unsigned char* g, unsigned char* b) | |
{ | |
*r = pixel[fb->vi.red.offset>>3]; | |
*g = pixel[fb->vi.green.offset>>3]; | |
*b = pixel[fb->vi.blue.offset>>3]; | |
return 0; | |
} | |
static int fb_unpack_argb32(FBInfo* fb, unsigned char* pixel, | |
unsigned char* r, unsigned char* g, unsigned char* b) | |
{ | |
*r = pixel[fb->vi.red.offset>>3]; | |
*g = pixel[fb->vi.green.offset>>3]; | |
*b = pixel[fb->vi.blue.offset>>3]; | |
return 0; | |
} | |
static int fb_unpack_none(FBInfo* fb, unsigned char* pixel, | |
unsigned char* r, unsigned char* g, unsigned char* b) | |
{ | |
*r = *g = *b = 0; | |
return 0; | |
} | |
static void set_pixel_unpacker(FBInfo* fb) | |
{ | |
if(fb_bpp(fb) == 2) | |
{ | |
fb->unpack = fb_unpack_rgb565; | |
} | |
else if(fb_bpp(fb) == 3) | |
{ | |
fb->unpack = fb_unpack_rgb24; | |
} | |
else if(fb_bpp(fb) == 4) | |
{ | |
fb->unpack = fb_unpack_argb32; | |
} | |
else | |
{ | |
fb->unpack = fb_unpack_none; | |
printf("%s: not supported format.\n", __func__); | |
} | |
return; | |
} | |
static int height = 0; | |
static int width = 0; | |
static int fb_open(FBInfo* fb, const char* fbfilename) | |
{ | |
fb->fd = open(fbfilename, O_RDWR); | |
if (fb->fd < 0) | |
{ | |
fprintf(stderr, "can't open %s\n", fbfilename); | |
return -1; | |
} | |
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) | |
goto fail; | |
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) | |
goto fail; | |
fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0); | |
if (fb->bits == MAP_FAILED) | |
goto fail; | |
if (height > 0) fb->vi.yres = height; | |
if (width > 0) fb->vi.xres = width; | |
printf("---------------framebuffer---------------\n"); | |
printf("%s: \n width : %8d\n height: %8d\n bpp : %8d\n r(%2d, %2d)\n g(%2d, %2d)\n b(%2d, %2d)\n", | |
fbfilename, fb->vi.xres, fb->vi.yres, fb_bpp(fb), | |
fb->vi.red.offset, fb->vi.red.length, | |
fb->vi.green.offset, fb->vi.green.length, | |
fb->vi.blue.offset, fb->vi.blue.length); | |
printf("-----------------------------------------\n"); | |
set_pixel_unpacker(fb); | |
return 0; | |
fail: | |
printf("%s is not a framebuffer.\n", fbfilename); | |
close(fb->fd); | |
return -1; | |
} | |
static void fb_close(FBInfo* fb) | |
{ | |
munmap(fb->bits, fb_size(fb)); | |
close(fb->fd); | |
return; | |
} | |
static int snap2jpg(const char * filename, int quality, FBInfo* fb) | |
{ | |
int row_stride = 0; | |
FILE * outfile = NULL; | |
struct jpeg_error_mgr jerr; | |
struct jpeg_compress_struct cinfo; | |
memset(&jerr, 0x00, sizeof(jerr)); | |
memset(&cinfo, 0x00, sizeof(cinfo)); | |
cinfo.err = jpeg_std_error(&jerr); | |
jpeg_create_compress(&cinfo); | |
if ((outfile = fopen(filename, "wb+")) == NULL) | |
{ | |
fprintf(stderr, "can't open %s\n", filename); | |
return -1; | |
} | |
jpeg_stdio_dest(&cinfo, outfile); | |
cinfo.image_width = fb_width(fb); | |
cinfo.image_height = fb_height(fb); | |
cinfo.input_components = 3; | |
cinfo.in_color_space = JCS_RGB; | |
jpeg_set_defaults(&cinfo); | |
jpeg_set_quality(&cinfo, quality, TRUE); | |
jpeg_start_compress(&cinfo, TRUE); | |
row_stride = fb_width(fb) * 2; | |
JSAMPROW * row_pointers; | |
//一次写入 | |
row_pointers = malloc(cinfo.image_height*cinfo.image_width*3); | |
unsigned int i = 0; | |
for(i = 0; i < cinfo.image_height; i++ ) | |
{ | |
row_pointers[i] = malloc(cinfo.image_width*3); | |
unsigned int j = 0; | |
int offset = 0; | |
unsigned char* line = fb->bits + i * cinfo.image_width * fb_bpp(fb); | |
for(j = 0; j < cinfo.image_width; j++, offset += 3, line += fb_bpp(fb)) | |
{ | |
fb->unpack(fb, line, row_pointers[i] + offset, row_pointers[i] + offset + 1, row_pointers[i] + offset + 2); | |
} | |
} | |
//All at once write | |
jpeg_write_scanlines(&cinfo, row_pointers, cinfo.image_height); | |
jpeg_finish_compress(&cinfo); | |
fclose(outfile); | |
for(i = 0; i < cinfo.image_height; i++ ) free(row_pointers[i]); | |
free(row_pointers); | |
jpeg_destroy_compress(&cinfo); | |
return 0; | |
} | |
//Ref: http://blog.chinaunix.net/space.php?uid=15059847&do=blog&cuid=2040565 | |
static int snap2png(const char * filename, int quality, FBInfo* fb) | |
{ | |
FILE *outfile; | |
if ((outfile = fopen(filename, "wb+")) == NULL) | |
{ | |
fprintf(stderr, "can't open %s\n", filename); | |
return -1; | |
} | |
/* prepare the standard PNG structures */ | |
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
png_infop info_ptr = png_create_info_struct(png_ptr); | |
/* setjmp() must be called in every function that calls a PNG-reading libpng function */ | |
if (setjmp(png_jmpbuf(png_ptr))) | |
{ | |
png_destroy_write_struct(&png_ptr, &info_ptr); | |
fclose(outfile); | |
return -1; | |
} | |
/* initialize the png structure */ | |
png_init_io(png_ptr, outfile); | |
// | |
int width = fb_width(fb); | |
int height = fb_height(fb); | |
int bit_depth = 8; | |
int color_type = PNG_COLOR_TYPE_RGB; | |
int interlace = 0; | |
png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type, | |
(!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7, | |
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); | |
/* write the file header information */ | |
png_write_info(png_ptr, info_ptr); | |
png_bytep* row_pointers; | |
row_pointers = (png_bytep*)malloc(height*sizeof(png_bytep)); | |
int i = 0; | |
int j = 0; | |
unsigned char* line = NULL; | |
for(i = 0; i < height; i++ ) | |
{ | |
row_pointers[i] = (png_bytep)malloc(sizeof(unsigned char)*width*3); | |
line = (unsigned char*)fb->bits + i * width * fb_bpp(fb); | |
for(j = 0; j < width; j++, line += fb_bpp(fb)) | |
{ | |
int offset = j * 3; | |
fb->unpack(fb, line, row_pointers[i]+offset, row_pointers[i]+offset+1, row_pointers[i]+offset+2); | |
} | |
} | |
//All at once write | |
png_write_image(png_ptr, row_pointers); | |
if (setjmp(png_jmpbuf(png_ptr))) | |
{ | |
printf("[write_png_file] Error during end of write"); | |
return -1; | |
} | |
png_write_end(png_ptr, NULL); | |
fclose(outfile); | |
for(i = 0; i < height; i++ ) free(row_pointers[i]); | |
free(row_pointers); | |
png_destroy_write_struct(&png_ptr, &info_ptr); | |
return 0; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
FBInfo fb; | |
char* filename = "/sdcard/screenshot.png"; | |
char* fbfilename = "/dev/graphics/fb0"; | |
int ch; | |
char* progname = argv[0]; | |
do { | |
ch = getopt(argc, argv, "o:f:w:h:"); | |
if (ch == EOF) | |
break; | |
switch (ch) { | |
case 'f': | |
fbfilename = optarg; | |
break; | |
case 'h': | |
height = atoi(optarg); | |
break; | |
case 'w': | |
width = atoi(optarg); | |
break; | |
case 'o': | |
filename = optarg; | |
break; | |
default: | |
printf("\nUsage: %s -f \"framebuffer dev\" -w \"width\" -h \"height\" -o \"output filename\"\n", progname); | |
printf(" framebuffer dev default: /dev/graphics/fb0\n"); | |
printf(" output filename default: /sdcard/screenshot.png\n"); | |
printf("Example: \n%s -o /sdcard/1.png\n", progname); | |
printf("%s -f /dev/graphics/fb0 -o /sdcard/1.jpg\n", progname); | |
printf("%s -w 1080 -h 1920 -o /sdcard/1.jpg\n", progname); | |
printf("-----------------------------------------------------------\n"); | |
return 1; | |
} | |
} while (1); | |
printf("\nSave to %s\n", filename); | |
memset(&fb, 0x00, sizeof(fb)); | |
if (fb_open(&fb, fbfilename) == 0) | |
{ | |
if(strstr(filename, ".png") != NULL) | |
{ | |
snap2png(filename, 100, &fb); | |
} | |
else | |
{ | |
snap2jpg(filename, 100, &fb); | |
} | |
fb_close(&fb); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment