音視頻入門-20-BMP几于、PNG蕊苗、JPG、GIF靜態(tài)圖生成GIF動態(tài)圖

* 音視頻入門文章目錄 *

靜態(tài)圖 -> 動態(tài)圖

前面 【18-手動生成一張GIF圖片】【19-使用giflib處理GIF圖片】 生成的 GIF 每一幀都是一個顏色沿彭,平時用到的 GIF 每一幀都是圖片朽砰,下面就做一張每一幀都是圖片的 GIF。

準備了 4 張靜態(tài)圖 .bmp 喉刘、 .png 瞧柔、 .jpg.gif(靜態(tài)的GIF):

BMP PNG JPG GIF
Android.bmp
Huawei.png
Fuchsia.jpg
iOS.gif
Android.bmp Huawei.png Fuchsia.jpg iOS.gif

每張圖片顯示 1 秒睦裳,生成 GIF:

image-to-gif-loop.gif

image to RGB

GIF 中使用 RGB 顏色索引來表示圖像造锅,每一幀圖像最多 256 個顏色。所以第一步廉邑,要將靜態(tài)圖片轉(zhuǎn)成 RGB哥蔚。

BMP to RGB

根據(jù) 【05-RGB-TO-BMP使用開源庫】 ,使用 libbmp 庫來完成 .bmp to RGB蛛蒙。

int decodeBMP(char *filename, unsigned char **bmpRGB) {
    bmp_img img;
    bmp_img_read(&img, filename);

    int width = img.img_header.biWidth;
    int height = img.img_header.biHeight;
    printf("Size: [%d, %d]\n", width, height);
    printf("BitCount: %d\n", img.img_header.biBitCount);
    printf("Compression: %d\n", img.img_header.biCompression);
    printf("SizeImage: %d\n", img.img_header.biSizeImage);

    *bmpRGB = malloc(width * height * 3);
    int x, y;
    unsigned char *BufferP;
    for (x = 0 ; x < height ; x++) {
        bmp_pixel *row = img.img_pixels[x];
        for (y = 0, BufferP = *bmpRGB+width*3*x; y < width; y++) {
            /* Get pixel's RGB values */
            bmp_pixel pixel = row[y];
            *BufferP++ = pixel.red;
            *BufferP++ = pixel.green;
            *BufferP++ = pixel.blue;
        }
    }
    return 0;
}

PNG to RGB

根據(jù) 【13-使用開源庫生成PNG圖片】 糙箍,使用 libpng 庫來完成 .png to RGB。

int decodePNG(char *filename, unsigned char **pngRGB) {
    FILE *fp = fopen(filename, "rb");
    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png) {
        fclose(fp);
        return -1;
    }

    png_infop info = png_create_info_struct(png);
    if(!info)  {
        fclose(fp);
        return -1;
    }

    if(setjmp(png_jmpbuf(png))) {
        fclose(fp);
        return -1;
    }

    png_init_io(png, fp);

    png_read_info(png, info);

    int width, height;
    png_byte color_type;
    png_byte bit_depth;
    png_bytep *row_pointers = NULL;

    width      = png_get_image_width(png, info);
    height     = png_get_image_height(png, info);
    color_type = png_get_color_type(png, info);
    bit_depth  = png_get_bit_depth(png, info);


    printf("PNG 圖片尺寸:【%d, %d】\n", width, height);
    printf("顏色類型:%d, 位深:%d\n", color_type, bit_depth);

    // Read any color_type into 8bit depth, RGBA format.
    // See http://www.libpng.org/pub/png/libpng-manual.txt

    if(bit_depth == 16)
        png_set_strip_16(png);

    if(color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png);

    // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
    if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand_gray_1_2_4_to_8(png);

    if(png_get_valid(png, info, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha(png);

    // These color_type don't have an alpha channel then fill it with 0xff.
    if(color_type == PNG_COLOR_TYPE_RGB ||
       color_type == PNG_COLOR_TYPE_GRAY ||
       color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_filler(png, 0xFF, PNG_FILLER_AFTER);

    if(color_type == PNG_COLOR_TYPE_GRAY ||
       color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

    png_read_update_info(png, info);
    int rowByteCount = png_get_rowbytes(png,info);
    printf("rowByteCount: %d\n", rowByteCount);

    row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
    for(int y = 0; y < height; y++) {
        row_pointers[y] = (png_byte*)malloc(rowByteCount);
    }

    png_read_image(png, row_pointers);

    *pngRGB = malloc(width*height*3);
    int counter = 0;
    for(int i = 0; i < height; i++) {
        if(color_type == 6) { // 帶有透明 RGBA
            for(int j = 0; j < rowByteCount; j+=4) {
                memcpy(*pngRGB+counter, row_pointers[i]+j, 3);
                counter+=3;
            }
        } else {
            memcpy(*pngRGB+rowByteCount, row_pointers[i], rowByteCount);
        }
    }

    fclose(fp);

    png_destroy_read_struct(&png, &info, NULL);

    return 0;
}

JPG to RGB

根據(jù) 【16-使用libjpeg-trubo處理JPEG圖片】 牵祟,使用 libjpeg-turbo 庫來完成 .jpg to RGB深夯。

int decodeJPG(char *filename, unsigned char **jpgRGB) {
    FILE *fp = fopen(filename, "rb");

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, fp);

    jpeg_read_header(&cinfo, TRUE);

    printf("image_width = %d\n", cinfo.image_width);
    printf("image_height = %d\n", cinfo.image_height);
    printf("num_components = %d\n", cinfo.num_components);

    printf("enter scale M/N:\n");

//    cinfo.out_color_space = JCS_YCbCr;
    printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);

    jpeg_start_decompress(&cinfo);

    //輸出的圖象的信息
    printf("output_width = %d\n", cinfo.output_width);
    printf("output_height = %d\n", cinfo.output_height);
    printf("output_components = %d\n", cinfo.output_components);

    int row_stride = cinfo.output_width * cinfo.output_components;
    /* Make a one-row-high sample array that will go away when done with image */
    JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
    buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);

    *jpgRGB = malloc(row_stride*cinfo.image_height);
    long counter = 0;
    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(*jpgRGB + counter, buffer[0], row_stride);
        counter += row_stride;
    }
    printf("total size: %ld\n", counter);

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(fp);

    return 0;
}

GIF to RGB

根據(jù) 【19-使用giflib處理GIF圖片】 ,使用 giflib 庫來完成 .gif to RGB诺苹。

int decodeGIF(char *filename, unsigned char **gifRGB) {
    int i, j, Size, Row, Col, Width, Height, ExtCode, Count;
    GifRecordType RecordType;
    GifByteType *Extension;
    GifRowType *ScreenBuffer;
    GifFileType *GifFile;
    int InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
        InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
    int ImageNum = 0;
    ColorMapObject *ColorMap;
    int Error;

    if ((GifFile = DGifOpenFileName(filename, &Error)) == NULL) {
        printf("Open File Error.\n");
        return -1;
    }

    if (GifFile->SHeight == 0 || GifFile->SWidth == 0) {
        printf("Image of width or height 0\n");
        return -1;
    }

    /*
     * Allocate the screen as vector of column of rows. Note this
     * screen is device independent - it's the screen defined by the
     * GIF file parameters.
     */
    if ((ScreenBuffer = (GifRowType *)
            malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL) {
        printf("Failed to allocate memory required, aborted.\n");
        return -1;
    }

    Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
    if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) { /* First row. */
        printf("Failed to allocate memory required, aborted.\n");
        return -1;
    }

    for (i = 0; i < GifFile->SWidth; i++)  /* Set its color to BackGround. */
        ScreenBuffer[0][i] = GifFile->SBackGroundColor;
    for (i = 1; i < GifFile->SHeight; i++) {
        /* Allocate the other rows, and set their color to background too: */
        if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL) {
            printf("Failed to allocate memory required, aborted.\n");
            return -1;
        }
        memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
    }

    int screenIndex = 0;
    /* Scan the content of the GIF file and load the image(s) in: */
    do {
        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
            printf("DGifGetRecordType Error.\n");
            return -1;
        }
        switch (RecordType) {
            case IMAGE_DESC_RECORD_TYPE:
                if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
                    printf("DGifGetImageDesc Error.\n");
                    return -1;
                }
                Row = GifFile->Image.Top; /* Image Position relative to Screen. */
                Col = GifFile->Image.Left;
                Width = GifFile->Image.Width;
                Height = GifFile->Image.Height;
                if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
                    GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
                    printf("Image %d is not confined to screen dimension, aborted.\n",ImageNum);
                    return -1;
                }
                if (GifFile->Image.Interlace) {
                    /* Need to perform 4 passes on the images: */
                    for (Count = i = 0; i < 4; i++)
                        for (j = Row + InterlacedOffset[i]; j < Row + Height;
                             j += InterlacedJumps[i]) {
                            if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
                                            Width) == GIF_ERROR) {
                                printf("DGifGetLine Error.\n");
                                return -1;
                            }
                        }
                }
                else {
                    for (i = 0; i < Height; i++) {
                        if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
                                        Width) == GIF_ERROR) {
                            printf("DGifGetLine Error.\n");
                            return -1;
                        }
                    }
                }

                /* Lets dump it - set the global variables required and do it: */
                ColorMap = (GifFile->Image.ColorMap
                            ? GifFile->Image.ColorMap
                            : GifFile->SColorMap);
                if (ColorMap == NULL) {
                    fprintf(stderr, "Gif Image does not have a colormap\n");
                    exit(EXIT_FAILURE);
                }

                /* check that the background color isn't garbage (SF bug #87) */
                if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
                    printf("Background color out of range for colormap\n");
                    return -1;
                }

                GifRowType GifRow;
                GifColorType *ColorMapEntry;
                unsigned char *BufferP;

                *gifRGB = malloc(GifFile->SWidth*GifFile->SHeight*3);

                for (i = 0; i <  GifFile->SHeight; i++) {
                    GifRow = ScreenBuffer[i];
                    for (j = 0, BufferP = *gifRGB+GifFile->SWidth*3*i; j < GifFile->SWidth; j++) {
                        ColorMapEntry = &ColorMap->Colors[GifRow[j]];
                        *BufferP++ = ColorMapEntry->Red;
                        *BufferP++ = ColorMapEntry->Green;
                        *BufferP++ = ColorMapEntry->Blue;
                    }
                }

                break;
            case EXTENSION_RECORD_TYPE:
                /* Skip any extension blocks in file: */
                if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
                    printf("DGifGetExtension Error.\n");
                    return -1;
                }
                while (Extension != NULL) {
                    if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
                        printf("DGifGetExtensionNext Error.\n");
                        return -1;
                    }
                }
                break;
            case TERMINATE_RECORD_TYPE:
                break;
            default:            /* Should be trapped by DGifGetRecordType. */
                break;
        }
    } while (RecordType != TERMINATE_RECORD_TYPE);

    (void)free(ScreenBuffer);

    if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) {
        printf("DGifCloseFile Error.\n");
        return -1;
    }
    return 0;
}

RGB 查看

ffplay -f rawvideo -pixel_format rgb24 -video_size 400x400 texture.rgb
image-to-rgb.jpg

RGB to GIF

將靜態(tài)圖轉(zhuǎn)成 RGB 以后塌西,就可以根據(jù) 【19-使用giflib處理GIF圖片】 使用 giflib 將 RGB 編碼成 GIF 動態(tài)圖。

完整步驟

#include <stdio.h>
......

int decodeBMP(char *, unsigned char **);
int decodePNG(char *, unsigned char **);
int decodeJPG(char *, unsigned char **);
int decodeGIF(char *, unsigned char **);
int encodeGIF(unsigned char **RGBBuffers, int NumOfRGBBuffer, char *GIFFileName,
              int ExpNumOfColors, int Width, int Height);

int main() {
    char *bmp = "/Users/staff/Desktop/Android.bmp";
    char *png = "/Users/staff/Desktop/Huawei.png";
    char *jpg = "/Users/staff/Desktop/Fuchsia.jpg";
    char *gif = "/Users/staff/Desktop/iOS.gif";

    unsigned char *bmpRGB = NULL;
    unsigned char *pngRGB = NULL;
    unsigned char *jpgRGB = NULL;
    unsigned char *gifRGB = NULL;

    printf("開始解碼 BMP 文件筝尾!\n");
    decodeBMP(bmp, &bmpRGB);
    char *androidRGB = "/Users/staff/Desktop/Android.rgb";
    FILE *androidRGBFile = fopen(androidRGB, "wb");
    fwrite(bmpRGB, 400*400*3, 1, androidRGBFile);
    fclose(androidRGBFile);
    printf("\n\n");

    printf("開始解碼 PNG 文件捡需!\n");
    decodePNG(png, &pngRGB);
    char *huaweiRGB = "/Users/staff/Desktop/Huawei.rgb";
    FILE *huaweiRGBFile = fopen(huaweiRGB, "wb");
    fwrite(pngRGB, 400*400*3, 1, huaweiRGBFile);
    fclose(huaweiRGBFile);
    printf("\n\n");

    printf("開始解碼 JPG 文件!\n");
    decodeJPG(jpg, &jpgRGB);
    char *fuchsiaRGB = "/Users/staff/Desktop/Fuchsia.rgb";
    FILE *fuchsiaRGBFile = fopen(fuchsiaRGB, "wb");
    fwrite(jpgRGB, 400*400*3, 1, fuchsiaRGBFile);
    fclose(fuchsiaRGBFile);
    printf("\n\n");

    printf("開始解碼 GIF 文件筹淫!\n");
    decodeGIF(gif, &gifRGB);
    char *iOSRGB = "/Users/staff/Desktop/iOS.rgb";
    FILE *iOSRGBFile = fopen(iOSRGB, "wb");
    fwrite(gifRGB, 400*400*3, 1, iOSRGBFile);
    fclose(iOSRGBFile);
    printf("\n\n");

    unsigned char **rgbBuffers = malloc(4*sizeof(unsigned char *));
    rgbBuffers[0] = bmpRGB;
    rgbBuffers[1] = pngRGB;
    rgbBuffers[2] = jpgRGB;
    rgbBuffers[3] = gifRGB;
    encodeGIF(rgbBuffers, 4, "/Users/staff/Desktop/image-to-gif.gif",
              7, 400, 400);

    free(bmpRGB);
    free(pngRGB);
    free(jpgRGB);
    free(gifRGB);

    return 0;
}

int decodeBMP(char *filename, unsigned char **bmpRGB) {
    ......
}

int decodePNG(char *filename, unsigned char **pngRGB) {
    ......
}

int decodeJPG(char *filename, unsigned char **jpgRGB) {
    ......
}

int decodeGIF(char *filename, unsigned char **gifRGB) {
    ......
}

int encodeGIF(unsigned char **RGBBuffers, int NumOfRGBBuffer, char *GIFFileName,
   ......
}

將 RGB 編碼成 GIF 的方法 encodeGIF:

int encodeGIF(unsigned char **RGBBuffers, int NumOfRGBBuffer, char *GIFFileName,
             int ExpNumOfColors, int Width, int Height) {
    int ColorMapSize;
    GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL, *OutputBuffer = NULL;
    ColorMapObject *OutputColorMap = NULL;

    // 打開輸出的 GIF 文件
    int Error;
    GifFileType *GifFile;
    if ((GifFile = EGifOpenFileName(GIFFileName, false, &Error)) == NULL) {
        PrintGifError(Error);
        printf("EGifOpenFileName Error.\n");
        return -1;
    }

    GifFile->SWidth = Width;
    GifFile->SHeight = Height;
    GifFile->SColorResolution = 1;
    GifFile->SBackGroundColor = 0;
    GifFile->SColorMap = NULL;

    unsigned long Size;
    GifByteType *RedP, *GreenP, *BlueP;
    GifByteType *Buffer, *BufferP;

    Size = ((long) Width) * Height * sizeof(GifByteType);
    if ((RedBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
        (GreenBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
        (BlueBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL) {
        return -1;
    }
    if ((Buffer = (GifByteType *) malloc(Width * 3)) == NULL) {
        return -1;
    }

    for(int i = 0; i < NumOfRGBBuffer; i++) {
        ColorMapSize = 1 << ExpNumOfColors;
        RedP = RedBuffer;
        GreenP = GreenBuffer;
        BlueP = BlueBuffer;
        int pointer = 0;
        for (int j = 0; j < Height; j++) {
            int k;
            memcpy(Buffer, RGBBuffers[i]+pointer, Width * 3);
            pointer+=Width*3;
            for (k = 0, BufferP = Buffer; k < Width; k++) {
                *RedP++ = *BufferP++;
                *GreenP++ = *BufferP++;
                *BlueP++ = *BufferP++;
            }
        }
        if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
            (OutputBuffer = (GifByteType *) malloc(Width * Height *
                                                   sizeof(GifByteType))) == NULL) {
            printf("Failed to allocate memory required, aborted.\n");
            return -1;
        }

        if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
                              RedBuffer, GreenBuffer, BlueBuffer,
                              OutputBuffer, OutputColorMap->Colors) == GIF_ERROR) {
            printf("GifQuantizeBuffer Error.\n");
            return -1;
        }

        printf("MakeSavedImage:%d\n", i);
        SavedImage *image = GifMakeSavedImage(GifFile, NULL);

        GifImageDesc *imageDesc = (GifImageDesc *) malloc(sizeof(GifImageDesc));
        imageDesc->Left = 0;
        imageDesc->Top = 0;
        imageDesc->Width = Width;
        imageDesc->Height = Height;
        imageDesc->Interlace = false;
        imageDesc->ColorMap = OutputColorMap;

        image->ImageDesc = *imageDesc;
        image->RasterBits = OutputBuffer;

        GraphicsControlBlock *GCB = (GraphicsControlBlock *) malloc(sizeof(GraphicsControlBlock));
        GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
        GCB->DelayTime = 100;
        GCB->UserInputFlag = false;
        GCB->TransparentColor = NO_TRANSPARENT_COLOR;

        printf("GCBToSaved:%d\n", i);
        EGifGCBToSavedExtension(GCB, GifFile, i);
    }
    free((char *) RedBuffer);
    free((char *) GreenBuffer);
    free((char *) BlueBuffer);

    printf("輸出 GIF 文件站辉。\n");
    // 輸出文件
    EGifSpew(GifFile);
    return 0;
}

查看 GIF

image-to-gif-preview.jpg

代碼:
audio-video-blog-demos

參考資料:

【音視頻入門-05-RGB-TO-BMP使用開源庫】

【音視頻入門-13-使用開源庫生成PNG圖片】

【音視頻入門-16-使用libjpeg-trubo處理JPEG圖片】

【音視頻入門-19-使用giflib處理GIF圖片】


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市损姜,隨后出現(xiàn)的幾起案子饰剥,更是在濱河造成了極大的恐慌,老刑警劉巖摧阅,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汰蓉,死亡現(xiàn)場離奇詭異,居然都是意外死亡棒卷,警方通過查閱死者的電腦和手機顾孽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門祝钢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人若厚,你說我怎么就攤上這事拦英。” “怎么了测秸?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵疤估,是天一觀的道長。 經(jīng)常有香客問我霎冯,道長铃拇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任沈撞,我火速辦了婚禮慷荔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘关串。我一直安慰自己,他們只是感情好监徘,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布晋修。 她就那樣靜靜地躺著,像睡著了一般凰盔。 火紅的嫁衣襯著肌膚如雪墓卦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天户敬,我揣著相機與錄音落剪,去河邊找鬼。 笑死尿庐,一個胖子當(dāng)著我的面吹牛忠怖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抄瑟,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凡泣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了皮假?” 一聲冷哼從身側(cè)響起鞋拟,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惹资,沒想到半個月后贺纲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡褪测,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年猴誊,在試婚紗的時候發(fā)現(xiàn)自己被綠了潦刃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡稠肘,死狀恐怖福铅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情项阴,我是刑警寧澤滑黔,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站环揽,受9級特大地震影響略荡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歉胶,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一汛兜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧通今,春花似錦粥谬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至臼氨,卻和暖如春掺喻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背储矩。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工感耙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人持隧。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓即硼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屡拨。 傳聞我的和親對象是個殘疾皇子谦絮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容