【iOS性能優(yōu)化】- 圖片顯示原理和優(yōu)化

圖片在計算機中如何存儲和表示?

常見的圖片格式

JPEG 是目前最常見的圖片格式捐晶,它誕生于1992年菲语,是一個很古老的格式。它只支持有損壓縮惑灵,其壓縮算法可以精確控制壓縮比山上,以圖像質(zhì)量換得存儲空間。由于它太過常見英支,以至于許多移動設(shè)備的 CPU 都支持針對它的硬編碼與硬解碼佩憾。

PNG 誕生在 1995 年,比 JPEG 晚幾年干花。它本身的設(shè)計目的是替代 GIF 格式妄帘,所以它與 GIF 有更多相似的地方。PNG 只支持無損壓縮池凄,所以它的壓縮比是有上限的抡驼。相對于 JPEG 和 GIF 來說,它最大的優(yōu)勢在于支持完整的透明通道肿仑。

GIF 誕生于 1987 年致盟,隨著初代互聯(lián)網(wǎng)流行開來碎税。它有很多缺點,比如通常情況下只支持 256 種顏色馏锡、透明通道只有 1 bit雷蹂、文件壓縮比不高。它唯一的優(yōu)勢就是支持多幀動畫眷篇,憑借這個特性,它得以從 Windows 1.0 時代流行至今荔泳,而且仍然大受歡迎蕉饼。

格式 優(yōu)點 缺點 用途
jpg 色彩豐富,文件小 有損壓縮 顏色豐富的圖
png 透明玛歌、無損壓縮昧港、簡單圖文件小 若顏色較多復(fù)雜,則圖片生成后的文件很大 小圖標支子、透明背景
gif 動態(tài)创肥、透明、文件小 色域不廣值朋、只有256種顏色 動態(tài)圖片

除了以上面常見的格式叹侄,也有一些新型的格式:

APNG 是 Mozilla 在 2008 年發(fā)布的一種圖片格式,旨在替換掉畫質(zhì)低劣的 GIF 動畫昨登。它實際上只是相當于 PNG 格式的一個擴展趾代,所以 Mozilla 一直想把它合并到 PNG 標準里面去。然而 PNG 開發(fā)組并沒有接受 APNG 這個擴展丰辣,而是一直在推進它自己的 MNG 動圖格式撒强。MNG 格式過于復(fù)雜以至于并沒有什么系統(tǒng)或瀏覽器支持,而 APNG 格式由于簡單容易實現(xiàn)笙什,目前已經(jīng)漸漸流行開來飘哨。Mozilla 自己的 Firefox 首先支持了 APNG,隨后蘋果的 Safari 也開始有了支持琐凭, Chrome 目前也已經(jīng)嘗試開始支持 芽隆,可以說未來前景很好

APNG 與 Gif 對比

WebP 是 Google 在 2010 年發(fā)布的圖片格式统屈,希望以更高的壓縮比替代 JPEG摆马。它用 VP8 視頻幀內(nèi)編碼作為其算法基礎(chǔ),取得了不錯的壓縮效果鸿吆。它支持有損和無損壓縮囤采、支持完整的透明通道、也支持多幀動畫惩淳,并且沒有版權(quán)問題蕉毯,是一種非常理想的圖片格式(美中不足的是乓搬,WebP格式圖像的編碼時間“比JPEG格式圖像長8倍)。借由 Google 在網(wǎng)絡(luò)世界的影響力代虾,WebP 在幾年的時間內(nèi)已經(jīng)得到了廣泛的應(yīng)用进肯。看看你手機里的 App:微博棉磨、微信江掩、QQ、淘寶乘瓤、網(wǎng)易新聞等等环形,每個 App 里都有 WebP 的身影。Facebook 則更進一步衙傀,用 WebP 來顯示聊天界面的貼紙動畫抬吟。

關(guān)于以上幾種圖片格式在移動端的解碼和性能對比參見:移動端圖片格式調(diào)研

iOS中圖片加載過程和性能瓶頸

如上文所說,大部分格式的圖片都是被壓縮的统抬,都需要被首先解碼為bitmap(未壓縮的位圖)火本,然后才能渲染到UI上。
UIImageView 顯示圖片聪建,也有類似的過程钙畔。實際上,一張圖片從在文件系統(tǒng)中金麸,到被顯示到 UIImageView刃鳄,會經(jīng)歷以下幾個步驟:

  1. 假設(shè)我們使用 +imageWithContentsOfFile: 方法從磁盤中加載一張圖片,這個時候的圖片并沒有解壓縮钱骂;
  2. 然后將生成的 UIImage 賦值給 UIImageView 叔锐;
  3. 接著一個隱式的 CATransaction 捕獲到了 UIImageView 圖層樹的變化;
  4. 在主線程的下一個 run loop 到來時见秽,Core Animation 提交了這個隱式的 transaction 愉烙,這個過程可能會對圖片進行 copy 操作,而受圖片是否字節(jié)對齊等因素的影響解取,這個 copy 操作可能會涉及以下部分或全部步驟:
    1. 分配內(nèi)存緩沖區(qū)用于管理文件 IO 和解壓縮操作敞葛;
    2. 將文件數(shù)據(jù)從磁盤讀到內(nèi)存中袜瞬;
    3. 將壓縮的圖片數(shù)據(jù)解碼成未壓縮的位圖形式,這是一個非常耗時的 CPU 操作;
    4. 最后 Core Animation 使用未壓縮的位圖數(shù)據(jù)渲染 UIImageView 的圖層吱殉。

在上面的步驟中肝集,我們提到了圖片的解壓縮是一個非常耗時的 CPU 操作恰聘,并且它默認是在主線程中執(zhí)行的魂挂。那么當需要加載的圖片比較多時,就會對我們應(yīng)用的響應(yīng)性造成嚴重的影響慧邮,尤其是在快速滑動的列表上调限,這個問題會表現(xiàn)得更加突出舟陆。這就是 UIImageView 的一個性能瓶頸。

實際上耻矮,當我們調(diào)用[UIImage imageNamed:@"xxx"]后秦躯,UIImage 中存儲的是未解碼的圖片,而調(diào)用 [UIImageView setImage:image]后裆装,會在主線程進行圖片的解碼工作并且將圖片顯示到 UI 上踱承,這時候,UIImage 中存儲的是解碼后的 bitmap 數(shù)據(jù)哨免。

為什么需要解壓縮

既然圖片的解壓縮需要消耗大量的 CPU 時間茎活,那么我們?yōu)槭裁催€要對圖片進行解壓縮呢?是否可以不經(jīng)過解壓縮铁瞒,而直接將圖片顯示到屏幕上呢妙色?答案是否定的桅滋。要想弄明白這個問題慧耍,我們首先需要知道什么是位圖

bitmap:bitmap 又叫位圖文件,它是一種非壓縮的圖片格式丐谋,所以體積非常大芍碧。所謂的非壓縮,就是圖片每個像素的原始信息在存儲器中依次排列号俐,一張典型的1920*1080像素的 bitmap 圖片泌豆,每個像素由 RGBA 四個字節(jié)表示顏色,那么它的體積就是 1920 * 1080 * 4 = 1012.5kb吏饿。

由于 bitmap 簡單順序存儲圖片的像素信息踪危,它可以不經(jīng)過解碼就直接被渲染到 UI 上。實際上猪落,其它格式的圖片都需要先被首先解碼為 bitmap贞远,然后才能渲染到界面上

不管是 JPEG 還是 PNG 圖片笨忌,都是一種壓縮的位圖圖形格式蓝仲。只不過 PNG 圖片是無損壓縮,并且支持 alpha 通道官疲,而 JPEG 圖片則是有損壓縮袱结,可以指定 0-100% 的壓縮比。值得一提的是途凫,在蘋果的 SDK 中專門提供了兩個函數(shù)用來生成 PNG 和 JPEG 圖片:

// return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format
UIKIT_EXTERN NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image);

// return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)                           
UIKIT_EXTERN NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality);

因此垢夹,在將磁盤中的圖片渲染到屏幕之前,必須先要得到圖片的原始像素數(shù)據(jù)维费,才能執(zhí)行后續(xù)的繪制操作棚饵,這就是為什么需要對圖片解壓縮的原因煤裙。

圖片解壓縮的過程其實就是將圖片的二進制數(shù)據(jù)轉(zhuǎn)換成像素數(shù)據(jù)的過程

圖片的編碼和解碼
iOS 底層是用 ImageIO.framework 實現(xiàn)的圖片編解碼。目前 iOS 原生支持的格式有:JPEG噪漾、JPEG2000硼砰、PNG、GIF欣硼、BMP题翰、ICO、TIFF诈胜、PICT豹障,自 iOS 8.0 起,ImageIO 又加入了 APNG焦匈、SVG血公、RAW 格式的支持。在上層缓熟,開發(fā)者可以直接調(diào)用 ImageIO 對上面這些圖片格式進行編碼和解碼累魔。對于動圖來說,開發(fā)者可以解碼動畫 GIF 和 APNG够滑、可以編碼動畫 GIF垦写。

注意:圖片所占內(nèi)存的大小與圖片的尺寸有關(guān),而不是圖片的文件大小

色彩空間和像素格式

計算圖片解碼后每行需要的比特數(shù)彰触,由兩個參數(shù)相乘得到:每行的像素數(shù) width梯投,和存儲一個像素需要的比特數(shù)4

這里的4,其實是由每張圖片的像素格式和像素組合來決定的况毅,下表是蘋果平臺支持的像素組合方式

image

)

表中的bpp分蓖,表示每個像素需要多少位;bpc表示顏色的每個分量尔许,需要多少位么鹤。具體的解釋方式,可以看下面這張圖:

image

我們解碼后的圖片母债,默認采用 kCGImageAlphaNoneSkipLast RGB 的像素組合午磁,沒有 alpha 通道,每個像素32位4個字節(jié)毡们,前三個字節(jié)代表紅綠藍三個通道, 但是有時候迅皇,如果我們只是繪制一個蒙版,是不需要這么字節(jié)表示的比如 Alpha 8 format衙熔,每個像素只需要占用 1 個字節(jié)登颓,這之間的差距就造成了內(nèi)存浪費。

UIGraphicsImageRenderer 和 UIGraphicsBeginImageContextWithOptions

當我們?yōu)榱穗x屏渲染红氯,要創(chuàng)建 image buffer 時框咙,我們通常會使用 UIGraphicsBeginImageContext咕痛,但是最好還是用 UIGraphicsImageRenderer,它的性能更好喇嘱、更高效茉贡,并且支持廣色域。這里有一個中間地帶者铜,如果你主要將圖像渲染到圖形圖像渲染器(graphic image render)中腔丧,該圖像可能使用超出 SRGB 色域的色彩空間值,但實際上并不需要更大的元素來存儲這些信息作烟。所以 UIImage 有一個可以用來獲取預(yù)構(gòu)建的 UIGraphicsImageRendererFormat 對象的 image renderer format 屬性愉粤,該對象用于重新渲染圖像時進行最優(yōu)化存儲。

所以蘋果官方建議使用 UIGraphicsImageRenderer拿撩,這個方法是從 iOS 10 引入衣厘,在 iOS 12 上會自動選擇最佳的圖像格式,可以減少很多內(nèi)存压恒。系統(tǒng)可以根據(jù)圖片分辨率選擇創(chuàng)建解碼圖片的格式影暴,如選用SRGB format 格式,每個像素占用 4 字節(jié)涎显,而Alpha 8 format坤检,每像素只占用 1 字節(jié)兴猩,可以減少大量的解碼內(nèi)存占用期吓。

擴展閱讀色彩空間與像素格式

imageWithContentsOfFile 和 imageNamed 對比

imgeNamed

用這個方法加載圖片分為兩種情況:

  1. 系統(tǒng)緩存有這個圖片,直接從緩存中取得
  2. 系統(tǒng)緩存沒有這個圖片
    通過傳入的文件名對整個工程進行遍歷 (在application bundle的頂層文件夾尋找名字的圖象 ), 如果如果找到對應(yīng)的圖片,iOS 系統(tǒng)首先要做的是將這個圖片放到系統(tǒng)緩存中去,以備下次使用的時候直接從系統(tǒng)緩存中取, 接下來重復(fù)第一步,即直接從緩存中取

由于系統(tǒng)會緩存圖片倾芝,所以如果要加載的這個圖片的文件量很多,文件大小很大,內(nèi)存不足,內(nèi)存泄露,甚至是程序的崩潰都是很容易發(fā)生的事.

imageWithContentsOfFile

用這個方法只有一種情況,那就是僅僅加載圖片, 圖像數(shù)據(jù)不會被緩存. 因此在加載較大圖片的時候, 以及圖片使用情況很少的時候可以使用這兩個方法 , 降低內(nèi)存消耗.

加載本地圖片讨勤,要比從Assets Catalogs耗時要長,具體見Assets Catalogs 與 I/O 優(yōu)化

圖片內(nèi)存優(yōu)化

到此我們可知晨另,圖片經(jīng)過解壓之后潭千,在內(nèi)存中實際是根據(jù)圖片的分辨率和圖片渲染所用的像素格式而定的

一、對不常用的大圖片借尿,使用 imageWithContentsOfFile 代替 imageNamed 方法刨晴,避免內(nèi)存緩存(相應(yīng)的使用imageNamed要避免載入大量的圖片造成內(nèi)存暴增)

二、使用 ImageIO 方法路翻,對大圖片進行縮放狈癞,減少圖片解碼占用內(nèi)存大小。

UIImage 在設(shè)置和調(diào)整大小的時候茂契,需要將原始圖像加壓到內(nèi)存中蝶桶,然后對內(nèi)部坐標空間做一系列轉(zhuǎn)換,整個過程會消耗很多資源掉冶。我們可以使用 ImageIO真竖,它可以直接讀取圖像大小和元數(shù)據(jù)信息脐雪,不會帶來額外的內(nèi)存開銷。

三恢共、繪制圖片战秋,用 UIGraphicsImageRenderer 代替 UIGraphicsBeginImageContextWithOptions,自動管理顏色格式

四讨韭、超大圖片處理

  1. 加載使用蘋果推薦的DownSampling方案(縮略圖方式)

     // DownSampling(降低采樣)
     // 在視圖比較小获询,圖片比較大的場景下,直接展示原圖片會造成不必要的內(nèi)存和CPU消耗拐袜,這里就可以使用ImageIO的接口吉嚣,DownSampling,也就是生成縮略圖
     func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage
     {
         let sourceOpt = [kCGImageSourceShouldCache : false] as CFDictionary
         /**<
          這里有兩個注意事項
    
          設(shè)置kCGImageSourceShouldCache為false蹬铺,避免緩存解碼后的數(shù)據(jù)尝哆,64位設(shè)置上默認是開啟緩存的,(很好理解甜攀,因為下次使用該圖片的時候秋泄,可能場景不同,需要生成的縮略圖大小是不同的规阀,顯然不能做緩存處理)
          設(shè)置kCGImageSourceShouldCacheImmediately為true恒序,避免在需要渲染的時候才做解碼,默認選項是false
          */
         // 其他場景可以用createwithdata (data并未decode,所占內(nèi)存沒那么大),
         let source = CGImageSourceCreateWithURL(imageURL as CFURL, sourceOpt)!
    
         let maxDimension = max(pointSize.width, pointSize.height) * scale
         let downsampleOpt = [kCGImageSourceCreateThumbnailFromImageAlways : true,
                              kCGImageSourceShouldCacheImmediately : true ,
                              kCGImageSourceCreateThumbnailWithTransform : true,
                              kCGImageSourceThumbnailMaxPixelSize : maxDimension] as CFDictionary
         let downsampleImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOpt)!
         return UIImage(cgImage: downsampleImage)
     }
    
    
  2. 使用蘋果的CATiledLayer去加載谁撼。原理是分片渲染歧胁,滑動時通過指定目標位置,通過映射原圖指定位置的部分圖片數(shù)據(jù)解碼渲染厉碟。這里不再累述喊巍,有興趣的小伙伴可以自行了解下官方API。

五箍鼓、網(wǎng)絡(luò)圖片加載方式:使用SDwebImage等三方庫

解決UIImageView的性能瓶頸

我們在討論UIImageView的性能瓶頸中發(fā)現(xiàn)崭参,問題在于主線程進行圖片解壓縮占用了大量的CPU,解決問題的辦法就是:在子線程提前對圖片進行強制解壓縮

而強制解壓縮的原理就是對圖片進行重新繪制款咖,得到一張新的解壓縮后的位圖何暮。其中,用到的最核心的函數(shù)是 CGBitmapContextCreate :

/* Create a bitmap context. The context draws into a bitmap which is `width'
   pixels wide and `height' pixels high. The number of components for each
   pixel is specified by `space', which may also specify a destination color
   profile. The number of bits for each component of a pixel is specified by
   `bitsPerComponent'. The number of bytes per pixel is equal to
   `(bitsPerComponent * number of components + 7)/8'. Each row of the bitmap
   consists of `bytesPerRow' bytes, which must be at least `width * bytes
   per pixel' bytes; in addition, `bytesPerRow' must be an integer multiple
   of the number of bytes per pixel. `data', if non-NULL, points to a block
   of memory at least `bytesPerRow * height' bytes. If `data' is NULL, the
   data for context is allocated automatically and freed when the context is
   deallocated. `bitmapInfo' specifies whether the bitmap should contain an
   alpha channel and how it's to be generated, along with whether the
   components are floating-point or integer. */
CG_EXTERN CGContextRef __nullable CGBitmapContextCreate(void * __nullable data,
    size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
    CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)
    CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

如果 UIImage 中存儲的是已經(jīng)解碼后的數(shù)據(jù)铐殃,速度就會快很多海洼,所以優(yōu)化的思路就是:在子線程中對圖片原始數(shù)據(jù)進行強制解碼,再將解碼后的圖片拋回主線程繼續(xù)使用背稼,從而提高主線程的響應(yīng)速度贰军。
我們需要使用的工具是 Core Graphics 框架的 CGBitmapContextCreate 方法和相關(guān)的繪制函數(shù)。總體的步驟是:

  1. 創(chuàng)建一個指定大小和格式的 bitmap context词疼。
  2. 將未解碼圖片寫入到這個 context 中俯树,這個過程包含了強制解碼。
  3. 從這個 context 中創(chuàng)建新的 UIImage 對象贰盗,返回许饿。

SDWebImage 實現(xiàn)

下面是SDWebImage的核心代碼:

// 1\. 從 UIImage 對象中獲取 CGImageRef 的引用。這兩個結(jié)構(gòu)是蘋果在不同層級上對圖片的表示方式舵盈,UIImage 屬于 UIKit陋率,是 UI 層級圖片的抽象,用于圖片的展示秽晚;CGImageRef 是 QuartzCore 中的一個結(jié)構(gòu)體指針瓦糟,用C語言編寫,用來創(chuàng)建像素位圖赴蝇,可以通過操作存儲的像素位來編輯圖片菩浙。這兩種結(jié)構(gòu)可以方便的互轉(zhuǎn):
CGImageRef imageRef = image.CGImage;

// 2\. 調(diào)用 UIImage 的 +colorSpaceForImageRef: 方法來獲取原始圖片的顏色空間參數(shù)。
CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];

size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);

// 3\. 計算圖片解碼后每行需要的比特數(shù)句伶,由兩個參數(shù)相乘得到:每行的像素數(shù) width劲蜻,和存儲一個像素需要的比特數(shù)4(這里的4,其實是由每張圖片的像素格式和像素組合來決定的)
size_t bytesPerRow = 4 * width;

// 4\. 最關(guān)鍵的函數(shù):調(diào)用 CGBitmapContextCreate() 方法考余,生成一個空白的圖片繪制上下文先嬉,我們傳入了上述的一些參數(shù),指定了圖片的大小楚堤、顏色空間疫蔓、像素排列等等屬性。
CGContextRef context = CGBitmapContextCreate(NULL,
                                             width,
                                             height,
                                             kBitsPerComponent,
                                             bytesPerRow,
                                             colorspaceRef,
                                             kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
    return image;
}

// 5\. 調(diào)用 CGContextDrawImage() 方法钾军,將未解碼的 imageRef 指針內(nèi)容鳄袍,寫入到我們創(chuàng)建的上下文中绢要,這個步驟吏恭,完成了隱式的解碼工作。
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

// 6\. 從 context 上下文中創(chuàng)建一個新的 imageRef重罪,這是解碼后的圖片了樱哼。
CGImageRef newImageRef = CGBitmapContextCreateImage(context);

// 7\. 從 imageRef 生成供UI層使用的 UIImage 對象,同時指定圖片的 scale 和 orientation 兩個參數(shù)剿配。
UIImage *newImage = [UIImage imageWithCGImage:newImageRef
                                        scale:image.scale
                                  orientation:image.imageOrientation];

CGContextRelease(context);
CGImageRelease(newImageRef);

return newImage;

通過以上的步驟搅幅,我們成功在子線程中對圖片進行了強制轉(zhuǎn)碼,回調(diào)給主線程使用呼胚,從而大大提高了圖片的渲染效率茄唐。這也是現(xiàn)在主流 App 和大量三方庫的最佳實踐。

SDWebImage配置優(yōu)化,減小CG-raster-data內(nèi)存占用

在使用SDWebImage的時候沪编,會默認保存圖片解碼后的內(nèi)存呼盆,以便提高頁面的渲染速度,但是這會導(dǎo)致內(nèi)存的急速增加蚁廓,所以可以在不影響體驗的情況下访圃,選擇機型和系統(tǒng),進行優(yōu)化相嵌,避免大量的內(nèi)存占用腿时,引起OOM問題。關(guān)閉解碼內(nèi)存緩存的方法如下:

[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];

附錄

WWDC2018 圖像和圖形的最佳實踐
WWDC2018 深入iOS內(nèi)存
移動端圖片格式調(diào)研
談?wù)?iOS 中圖片的解壓縮
iOS開發(fā):圖片格式與性能優(yōu)化

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饭宾,一起剝皮案震驚了整個濱河市批糟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌看铆,老刑警劉巖跃赚,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異性湿,居然都是意外死亡纬傲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門肤频,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叹括,“玉大人,你說我怎么就攤上這事宵荒≈祝” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵报咳,是天一觀的道長侠讯。 經(jīng)常有香客問我,道長暑刃,這世上最難降的妖魔是什么厢漩? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮岩臣,結(jié)果婚禮上溜嗜,老公的妹妹穿的比我還像新娘。我一直安慰自己架谎,他們只是感情好炸宵,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谷扣,像睡著了一般土全。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天裹匙,我揣著相機與錄音野哭,去河邊找鬼。 笑死幻件,一個胖子當著我的面吹牛拨黔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绰沥,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼篱蝇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了徽曲?” 一聲冷哼從身側(cè)響起零截,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秃臣,沒想到半個月后涧衙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡奥此,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年弧哎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稚虎。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡撤嫩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蠢终,到底是詐尸還是另有隱情序攘,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布寻拂,位于F島的核電站程奠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏祭钉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扒接,春花似錦碱呼、人聲如沸愚臀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茴厉。三九已至矾缓,卻和暖如春而账,著一層夾襖步出監(jiān)牢的瞬間泞辐,已是汗流浹背咐吼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肌幽,地道東北人喂急。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓糕簿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苗膝。 傳聞我的和親對象是個殘疾皇子辱揭,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345