圖片基礎(chǔ)知識(shí)梳理(3) - Bitmap&BitmapFactory 解析

一铲敛、概述

今天這篇文章我們來了解一下兩個(gè)類:

  • Bitmap
  • BitmapFactory

二界弧、Bitmap

2.1 創(chuàng)建Bitmap

通過Bitmap的源碼场刑,我們可以看到它內(nèi)部提供了很多.createBitmap(xxx)的靜態(tài)方法证芭,我們可以通過這些方法來獲得一個(gè)Bitmap


上述的方法最終可以分為以下三類:

  • 通過一個(gè)已有的Bitmap創(chuàng)建
  • 創(chuàng)建一個(gè)空的Bitmap
  • 創(chuàng)建一個(gè)新的Bitmap朦肘,該Bitmap每個(gè)像素點(diǎn)的顏色通過一個(gè)colors[]數(shù)組指定。

下面损趋,我們來看一下這三類方法對(duì)于Bitmap的生產(chǎn)過程:

第一類

    public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
            Matrix m, boolean filter) {

        checkXYSign(x, y);
        checkWidthHeight(width, height);
        //新的bitmap范圍不能大于原始的bitmap
        if (x + width > source.getWidth()) {
            throw new IllegalArgumentException("x + width must be <= bitmap.width()");
        }
        if (y + height > source.getHeight()) {
            throw new IllegalArgumentException("y + height must be <= bitmap.height()");
        }

        //如果滿足下面這些條件患久,那么直接返回原始的bitmap
        if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
                height == source.getHeight() && (m == null || m.isIdentity())) {
            return source;
        }

        int neww = width;
        int newh = height;
        Canvas canvas = new Canvas();
        Bitmap bitmap;
        Paint paint;
        //生成bitmap對(duì)應(yīng)區(qū)域
        Rect srcR = new Rect(x, y, x + width, y + height);
        //原始bitmap對(duì)應(yīng)區(qū)域
        RectF dstR = new RectF(0, 0, width, height);

        Config newConfig = Config.ARGB_8888;
        //獲得原始bitmap的config
        final Config config = source.getConfig();
        // GIF files generate null configs, assume ARGB_8888
        if (config != null) {
            switch (config) {
                case RGB_565:
                    newConfig = Config.RGB_565;
                    break;
                case ALPHA_8:
                    newConfig = Config.ALPHA_8;
                    break;
                //noinspection deprecation
                case ARGB_4444:
                case ARGB_8888:
                default:
                    newConfig = Config.ARGB_8888;
                    break;
            }
        }
        //如果不需要變換胡本,那么創(chuàng)建一個(gè)空的bitmap.
        if (m == null || m.isIdentity()) {
            bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
            paint = null;   // not needed
        } else {
            //根據(jù)Matrix共啃,對(duì)原始的bitmap進(jìn)行一些變換操作.
            final boolean transformed = !m.rectStaysRect();

            RectF deviceR = new RectF();
            m.mapRect(deviceR, dstR);

            neww = Math.round(deviceR.width());
            newh = Math.round(deviceR.height());

            bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
                    transformed || source.hasAlpha());

            canvas.translate(-deviceR.left, -deviceR.top);
            canvas.concat(m);

            paint = new Paint();
            paint.setFilterBitmap(filter);
            if (transformed) {
                paint.setAntiAlias(true);
            }
        }
        //返回bitmap的這些屬性和原始bitmap相同
        bitmap.mDensity = source.mDensity;
        bitmap.setHasAlpha(source.hasAlpha());
        bitmap.setPremultiplied(source.mRequestPremultiplied);

        //設(shè)置canvas對(duì)應(yīng)的bitmap為返回的bitmap
        canvas.setBitmap(bitmap);

        //通過canvas把原始的bitmap繪制上去.
        canvas.drawBitmap(source, srcR, dstR, paint);

        //重新置為空.
        canvas.setBitmap(null);
        return bitmap;
    }
  • 方法作用:返回原始的Bitmap中一個(gè)不可改變的子集,返回的Bitmap有可能是原始的Bitmap(原始的Bitmap不可改變夫嗓,并且大小和請(qǐng)求的新的Bitmap大小和原來一樣)桐玻,也有可能是復(fù)制出來的篙挽,它和原始的Bitmapdensity相同。
  • 參數(shù)說明:
  • source:原始的Bitmap
  • x, y:在原始的Bitmap中的起始坐標(biāo)镊靴。
  • width, height:返回的Bitmap的寬高铣卡,如果超過了原始Bitmap的范圍,那么會(huì)拋出異常偏竟。
  • mMatrix類型煮落,表示需要的變換
  • filter:是否需要優(yōu)化,只有當(dāng)m不只有平移操作時(shí)才去進(jìn)行踊谋。

第二類

    private static Bitmap createBitmap(DisplayMetrics display, int width, int height, Config config, boolean hasAlpha) {
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("width and height must be > 0");
        }
        Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
        if (display != null) {
            bm.mDensity = display.densityDpi;
        }
        bm.setHasAlpha(hasAlpha);
        if (config == Config.ARGB_8888 && !hasAlpha) {
            nativeErase(bm.mNativePtr, 0xff000000);
        }
        return bm;
    }
  • 方法作用:返回一個(gè)可變的bitmap蝉仇,它的density由傳入的DisplayMetrics指定。
  • 參數(shù)說明:
  • displayBitmap將要被繪制的Display metrics
  • width, heightbitmap的寬高
  • config:配置信息,對(duì)應(yīng)ARGB_8888那些轿衔。
  • hasAlpha:如果bitmap的屬性是ARGB_8888沉迹,那么這個(gè)標(biāo)志為可以用來把bitmap標(biāo)志為透明,它會(huì)把bitmap中的黑色像素轉(zhuǎn)換為透明害驹。

第三類

    public static Bitmap createBitmap(DisplayMetrics display, int colors[],
            int offset, int stride, int width, int height, Config config) {

        checkWidthHeight(width, height);
        if (Math.abs(stride) < width) {
            throw new IllegalArgumentException("abs(stride) must be >= width");
        }
        int lastScanline = offset + (height - 1) * stride;
        int length = colors.length;
        if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
                (lastScanline + width > length)) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("width and height must be > 0");
        }
        Bitmap bm = nativeCreate(colors, offset, stride, width, height,
                            config.nativeInt, false);
        if (display != null) {
            bm.mDensity = display.densityDpi;
        }
        return bm;
    }
  • 方法作用:返回一個(gè)不可變的bitmap對(duì)象鞭呕,它的長(zhǎng)寬由width/height指定,每個(gè)像素點(diǎn)的顏色通過colos[]數(shù)組得到宛官,初始的density來自于DisplayMetrics葫松。
  • 方法參數(shù):
  • displayBitmap將要被繪制的Display metrics
  • colors:用來初始化像素點(diǎn)的顏色
  • offset:第一個(gè)像素點(diǎn)的顏色在數(shù)組當(dāng)中跳過的個(gè)數(shù)。
  • stride:兩行之間需要跳過的顏色個(gè)數(shù)底洗。
  • width/height:寬高进宝。
  • config:對(duì)應(yīng)ARGB_8888那些。

2.2 壓縮bitmap

    public boolean compress(CompressFormat format, int quality, OutputStream stream) {
        checkRecycled("Can't compress a recycled bitmap");
        // do explicit check before calling the native method
        if (stream == null) {
            throw new NullPointerException();
        }
        if (quality < 0 || quality > 100) {
            throw new IllegalArgumentException("quality must be 0..100");
        }
        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
        boolean result = nativeCompress(mNativePtr, format.nativeInt,
                quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        return result;
    }
  • 方法作用:把當(dāng)前這個(gè)bitmap的壓縮版本寫入到某個(gè)輸出流當(dāng)中枷恕,如果返回true党晋,那么這個(gè)bitmap可以被BitmapFactory.decodeStream()恢復(fù)。需要注意的是徐块,并不是所有的bitmap都支持所有的格式未玻,因此,通過BitmapFactory恢復(fù)回來的bitmap有可能和原來不同胡控。
  • 方法參數(shù):
  • CompressFormat是一個(gè)枚舉類型扳剿,它的值有JPEG/PNG/WEBP
  • quality對(duì)應(yīng)0-100
  • stream則是壓縮后結(jié)果的輸出流。

2.3 回收bitmap

    public void recycle() {
        if (!mRecycled && mNativePtr != 0) {
            if (nativeRecycle(mNativePtr)) {
                // return value indicates whether native pixel object was actually recycled.
                // false indicates that it is still in use at the native level and these
                // objects should not be collected now. They will be collected later when the
                // Bitmap itself is collected.
                mBuffer = null;
                mNinePatchChunk = null;
            }
            mRecycled = true;
        }
    }

recycle方法主要做幾件事:

  • 釋放和這個(gè)bitmap關(guān)聯(lián)的native對(duì)象
  • 清除像素?cái)?shù)據(jù)mBuffer的引用昼激,但是這一過程不是同步的庇绽,它只是將引用置為空,等待垃圾回收器將它回收橙困。
  • 在調(diào)用這個(gè)方法之后瞧掺,mRecycled標(biāo)志位就為true,之后如果再調(diào)用bitmap的方法凡傅,那么很有可能發(fā)生異常辟狈。
  • 一般情況下,我們不需要手動(dòng)調(diào)用這個(gè)方法夏跷,因?yàn)楫?dāng)這個(gè)bitmap不被引用時(shí)哼转,垃圾回收器就會(huì)自動(dòng)回收它所占用的內(nèi)存。

2.4 獲取Bitmap所占內(nèi)存

  • getAllocationByteCount()
    返回存儲(chǔ)這個(gè)bitmap對(duì)象所需要的內(nèi)存槽华,當(dāng)我們對(duì)bitmap所占內(nèi)存區(qū)域進(jìn)行復(fù)用的時(shí)候壹蔓,這個(gè)函數(shù)的返回結(jié)果可能要大于getByteCount的值,否則猫态,它和getByteCount的值是相同的佣蓉。
    這個(gè)值煮纵,在bitmap整個(gè)生命周期之內(nèi)都不會(huì)改變。
    public final int getAllocationByteCount() {
        if (mBuffer == null) {
            return getByteCount();
        }
        return mBuffer.length;
    }
  • getByteCount
    表示存儲(chǔ)bitmap像素所需要的最小字節(jié)偏螺,自從4.4之后,這個(gè)就不能用來確定bitmap占用的內(nèi)存了匆光,需要用getAllocationByteCount套像。
    public final int getByteCount() {
        // int result permits bitmaps up to 46,340 x 46,340
        return getRowBytes() * getHeight();
    }

2.5 獲取縮放后大小


我們可以通過上面這六個(gè)方法獲得縮放后的寬高,它們的原理就是傳入一個(gè)目標(biāo)的density终息,然后和當(dāng)前bitmapdensity進(jìn)行比較夺巩,然后算出一個(gè)縮放的倍數(shù),在和原來的大小相乘周崭。目標(biāo)density的來源有以下三個(gè):

  • 直接傳入
  • Canvasdensity
  • DisplayMetricsdensity

計(jì)算的規(guī)則為:

    static public int scaleFromDensity(int size, int sdensity, int tdensity) {
        if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
            return size;
        }

        // Scale by tdensity / sdensity, rounding up.
        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
    }

三柳譬、BitmapFactory

BitmapFactory用來從多種不同的來源獲得Bitmap

  • 文件、文件描述符
  • 資源文件Resource
  • byte[]數(shù)組
  • 輸入流InputStream

3.1 BitmapFactory.Options

  • Bitmap inBitmap
    如果給Options設(shè)置了這個(gè)Bitmap续镇,那么在通過這個(gè)Options解碼的時(shí)候美澳,解碼方法返回的bitmap會(huì)嘗試復(fù)用這個(gè)Options中的bitmap,如果不能復(fù)用摸航,那么解碼方法會(huì)返回null制跟,并拋出異常,它要求復(fù)用的bitmap是可變的酱虎。
    4.4以后雨膨,只要求新申請(qǐng)的bitmapgetByteCount()小于等于Options中的bitmapgetAllocationByteCount()就可以。
    4.4以前读串,格式必須是jpeg/png聊记,并且要求兩個(gè)bitmap相同并且inSampleSize1
  • boolean inJustDecodeBounds
    如果設(shè)為true恢暖,那么解碼方法的返回值null排监,但是它會(huì)設(shè)置outXXX的值,這樣調(diào)用者就可以在不用解碼整張圖片的前提下查詢到這個(gè)bitmap的長(zhǎng)寬杰捂。
  • int inSampleSize
    對(duì)原來的圖片進(jìn)行采樣社露,如果inSampleSize4,那么圖片的長(zhǎng)寬會(huì)縮短為原來的1/4琼娘,這樣就可以減少bitmap占用的內(nèi)存峭弟。
  • Bitmap.Config inPreferredConfig
    圖片解碼的格式要求。
  • 縮放相關(guān)的標(biāo)志:inScaled脱拼、inDensity瞒瘸、inTargetDensityinScreenDensity
    首先熄浓,只有在inScaledtrue的時(shí)候情臭,縮放的機(jī)制才會(huì)生效省撑,這個(gè)值默認(rèn)是true的。
  • inDensity
    我們先討論一下inDensity俯在,當(dāng)我們沒有給density賦值的時(shí)候竟秫,系統(tǒng)會(huì)給我們初始化它:
        //如果沒有設(shè)置density
        if (opts.inDensity == 0 && value != null) {
            final int density = value.density; //這里的TypeValue會(huì)根據(jù)存放文件夾的不同而不同.
            if (density == TypedValue.DENSITY_DEFAULT) {
                opts.inDensity = DisplayMetrics.DENSITY_DEFAULT; //如果density為0,那么把density設(shè)置為160.
            } else if (density != TypedValue.DENSITY_NONE) {
                opts.inDensity = density; //否則跷乐,設(shè)置為value中的density.
            }
        }
  • inTargetDensity
    再來看一下inTargetDensity肥败,它得到的就是屏幕的density.
        if (opts.inTargetDensity == 0 && res != null) {
            opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
        }
  • inScreenDensity
    最后inScreenDensity沒有被賦予默認(rèn)值,也就是說它為0愕提,如果我們期望圖片不要被縮放馒稍,那么就要給它設(shè)置為手機(jī)的density

這三者的關(guān)系是:當(dāng)inDensity不為0并且inTargetDensity不為0浅侨,inDensityinScreenDensity不相等時(shí)纽谒,會(huì)對(duì)圖片進(jìn)行縮放,縮放倍數(shù)為inTargetDensity/inDensity如输。

這樣說可能比較抽象鼓黔,我們舉一個(gè)實(shí)際的例子,假如我們的手機(jī)的density320dpi的不见,那么inTargetDensity就等于320请祖,這時(shí)候我們把某張圖片資源放在了drawable-xxxhpi下,那么inDensity的值就為640脖祈,我們沒有設(shè)置inScreenDensity肆捕,那么它的默認(rèn)值是0,這時(shí)候滿足:

inDensity != 0 && inTargetDensity != 0 && inDensity != inScreenDensity

圖片就會(huì)進(jìn)行縮放盖高,縮放的倍數(shù)就為320/640慎陵,也就是說最終得到的bitmap的長(zhǎng)寬是原來的一半。

  • outXXX
    這個(gè)返回的結(jié)果和inJustDecodeBounds有關(guān)喻奥,如果inJustDecodeBoundstrue席纽,那么返回的是沒有經(jīng)過縮放的大小,如果為false撞蚕,那么就是縮放后的大小润梯。

3.2 獲取bitmap方法

下面是BitmapFactory提供的方法:


所有的獲取bitmap最終都是調(diào)用了一下四個(gè)方法Native方法其中之一,可以看到它可以從這些來源讀壬谩:

  • file
  • byte[]
  • InputStream

其中有個(gè)需要注意的是Rect纺铭,這是一個(gè)傳入的值,在讀取資源完畢后刀疙,它會(huì)寫入讀取資源的padding舶赔,如果沒有那么為[-1, -1, -1,- 1],而如果返回的bitmap為空谦秧,那么傳入的值不會(huì)改變竟纳。

四撵溃、Bitmap的轉(zhuǎn)換方法

public class BitmapConvertUtils {

    public static Bitmap fromResourceIdAutoScale(Resources resources, int resourceId, BitmapFactory.Options options) {
        return BitmapFactory.decodeResource(resources, resourceId, options);
    }

    public static Bitmap fromResourceIdNotScale(Resources resources, int resourceId, Rect rect, BitmapFactory.Options options) {
        InputStream resourceStream = null;
        Bitmap bitmap = null;
        try {
            resourceStream = resources.openRawResource(resourceId);
            bitmap = BitmapFactory.decodeStream(resourceStream, rect, options);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (resourceStream != null) {
                    resourceStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    public static Bitmap fromAssert(Context context, String assertFilePath, Rect rect, BitmapFactory.Options options) {
        Bitmap bitmap = null;
        InputStream assertStream = null;
        AssetManager assetManager = context.getAssets();
        try {
            assertStream = assetManager.open(assertFilePath);
            bitmap = BitmapFactory.decodeStream(assertStream, rect, options);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (assertStream != null) {
                    assertStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return bitmap;
    }

    public static Bitmap fromByteArray(byte[] byteArray, int offset, int length, BitmapFactory.Options options) {
        return BitmapFactory.decodeByteArray(byteArray, offset, length, options);
    }

    public static Bitmap fromFile(String filePath, BitmapFactory.Options options) {
        return BitmapFactory.decodeFile(filePath, options);
    }

    public static Bitmap fromDrawable(Drawable drawable) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        if (bitmap != null) {
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, width, height);
            drawable.draw(canvas);
            return bitmap;
        }
        return null;
    }

    public static Bitmap fromView(View view) {
        view.clearFocus();
        view.setPressed(false);
        boolean willNotCache = view.willNotCacheDrawing();
        view.setWillNotCacheDrawing(false);
        int color = view.getDrawingCacheBackgroundColor();
        view.setDrawingCacheBackgroundColor(color);
        if (color != 0) {
            view.destroyDrawingCache();
        }
        view.buildDrawingCache();
        Bitmap cacheBitmap = view.getDrawingCache();
        if (cacheBitmap == null) {
            return null;
        }
        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
        view.destroyDrawingCache();
        view.setWillNotCacheDrawing(willNotCache);
        view.setDrawingCacheBackgroundColor(color);
        return bitmap;
    }

    public static Bitmap fromInputStream(InputStream inputStream) {
        return BitmapFactory.decodeStream(inputStream);
    }

    public static byte[] toByteArray(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
        byte[] bytes = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(format, quality, outputStream);
        bytes = outputStream.toByteArray();
        try {
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

    public static Drawable toDrawable(Resources resources, Bitmap bitmap) {
        return new BitmapDrawable(resources, bitmap);
    }

    public static void toFile(Bitmap bitmap, Bitmap.CompressFormat format, int quality, String path) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(path);
            bitmap.compress(format, quality, fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锥累,隨后出現(xiàn)的幾起案子缘挑,更是在濱河造成了極大的恐慌,老刑警劉巖桶略,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件语淘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡删性,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門焕窝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹬挺,“玉大人,你說我怎么就攤上這事它掂“桶铮” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵虐秋,是天一觀的道長(zhǎng)榕茧。 經(jīng)常有香客問我,道長(zhǎng)客给,這世上最難降的妖魔是什么用押? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮靶剑,結(jié)果婚禮上蜻拨,老公的妹妹穿的比我還像新娘。我一直安慰自己桩引,他們只是感情好缎讼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坑匠,像睡著了一般血崭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厘灼,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天夹纫,我揣著相機(jī)與錄音,去河邊找鬼设凹。 笑死捷凄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的围来。 我是一名探鬼主播跺涤,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼匈睁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了桶错?” 一聲冷哼從身側(cè)響起航唆,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎院刁,沒想到半個(gè)月后糯钙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡退腥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年任岸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狡刘。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡享潜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嗅蔬,到底是詐尸還是另有隱情剑按,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布澜术,位于F島的核電站艺蝴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸟废。R本人自食惡果不足惜猜敢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盒延。 院中可真熱鬧锣枝,春花似錦、人聲如沸兰英。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽畦贸。三九已至陨闹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薄坏,已是汗流浹背趋厉。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胶坠,地道東北人君账。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像沈善,于是被迫代替她去往敵國(guó)和親乡数。 傳聞我的和親對(duì)象是個(gè)殘疾皇子椭蹄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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