Raw File
screenshot.c
/* PPM screenshots */

#include "dryos.h"
#include "bmp.h"
#include "imgconv.h"
#include "beep.h"
#include "screenshot.h"

#ifdef FEATURE_SCREENSHOT

int take_screenshot( char* filename, uint32_t mode )
{
    /* image buffers */
    uint8_t * rgb = 0;
    uint8_t * bmp_copy = 0;
    uint32_t * yuv_copy = 0;
    
    beep();
    info_led_on();
    
    /* what to save? */
    int save_bmp = mode & SCREENSHOT_BMP;
    int save_yuv = mode & SCREENSHOT_YUV;
    
    uint8_t* bvram = bmp_vram();
    uint32_t* lvram = (uint32_t*) get_yuv422_vram()->vram;
    
    if (!lvram)
    {
        /* can we save the YUV buffer? (it might be uninitialized, e.g. in photo mode before going to LV) */
        save_yuv = 0;
    }

    /* do a fast temporary copy of the VRAMs to minimize motion artifacts (tearing) */
    bmp_copy = tmp_malloc(720 * 480);
    yuv_copy = tmp_malloc(vram_lv.width * vram_lv.pitch);
    if (!bmp_copy) goto err;
    if (!yuv_copy) goto err;
    
    memcpy(yuv_copy, lvram, vram_lv.width * vram_lv.pitch);
    for (int y = 0; y < 480; y++)
    {
        memcpy(bmp_copy + y*720, &bvram[BM(0,y)], 720);
    }

    /* setup output buffer */
    /* todo: support HDMI resolutions? */
    rgb = fio_malloc(720 * 480 * 3);
    if (!rgb) goto err;
    
    /* fill it with data */
    for (int y = 0; y < 480; y++)
    {
        for (int x = 0; x < 720; x++)
        {
            int p = 0;
            uint8_t Y = 0; int8_t U = 0; int8_t V = 0;
            uint32_t pal = 0; uint8_t opacity = 0;
            
            if (save_bmp)
            {
                /* get pixel at (x,y) */
                p = bmp_copy[x + y*720];
                
                /* get palette entry (including our DIGIC pokes, if any) */
                pal = shamem_read(LCD_Palette[3*p]);
                if (!pal) pal = LCD_Palette[3*p + 2];
                opacity = (pal >> 24) & 0xFF;
                Y = (pal >> 16) & 0xFF;
                U = (pal >>  8) & 0xFF;
                V = (pal >>  0) & 0xFF;
            }
            else
            {
                /* don't save BMP overlay => just pretend the entire palette is transparent */
                pal = 0x00FF0000;
            }
            
            uint32_t uyvy = 0;

            /* handle transparency (incomplete, needs more reverse engineering) */
            if (pal == 0x00FF0000) /* fully transparent */
            {
                if (save_yuv)
                {
                    uyvy = yuv422_get_pixel(yuv_copy, BM2LV(x,y)/2);
                }
                Y = UYVY_GET_AVG_Y(uyvy);
                U = UYVY_GET_U(uyvy);
                V = UYVY_GET_V(uyvy);
            }
            else if (opacity == 0 || opacity == 1)  /* semi-transparent? */
            {
                if (save_yuv)
                {
                    uyvy = yuv422_get_pixel(yuv_copy, BM2LV(x,y)/2);
                }
                uint8_t Y2 = UYVY_GET_AVG_Y(uyvy);
                int8_t U2 = UYVY_GET_U(uyvy);
                int8_t V2 = UYVY_GET_V(uyvy);
                
                Y = ((int)Y + (int)Y2) / 2;
                U = ((int)U + (int)U2) / 2;
                V = ((int)V + (int)V2) / 2;
            }
            /* other transparency codes? */
            
            /* convert to RGB */
            int R,G,B;
            yuv2rgb(Y, U, V, &R, &G, &B);
            
            /* copy to our buffer */
            rgb[(y*720 + x)*3    ] = R;
            rgb[(y*720 + x)*3 + 1] = G;
            rgb[(y*720 + x)*3 + 2] = B;
        }
    }
    info_led_off();

    /* no longer needed, output image created */
    free(bmp_copy); bmp_copy = 0;
    free(yuv_copy); yuv_copy = 0;

    /* output filename */
    char path[100];
    
    if (filename == SCREENSHOT_FILENAME_AUTO)
    {
        get_numbered_file_name("VRAM%d.PPM", 9999, path, sizeof(path));
    }
    else
    {
        if (strchr(filename, '%'))
        {
            get_numbered_file_name(filename, 9999, path, sizeof(path));
        }
        else
        {
            snprintf(path, sizeof(path), "%s", filename);
        }
    }

    FILE *f = FIO_CreateFile(path);
    if (!f)
    {
        goto err;
    }
    
    /* 8-bit RGB */
    my_fprintf(f, "P6\n720 480\n255\n");
    FIO_WriteFile(f, rgb, 720*480*3);
    FIO_CloseFile(f);
    free(rgb);
    return 1;

err:
    if (rgb) free(rgb);
    if (bmp_copy) free(bmp_copy);
    if (yuv_copy) free(yuv_copy);
    info_led_off();
    return 0;
}
#endif
back to top