iOS自定義水印相機

前段時間公司的項目需要做自己的自定義相機和照片水印。抽空記一下筆記。文末有Demo

實現了相機的自定義 和水印、濾鏡相關功能。image處理方式都是用類別的方式。
后面我會把詳細的demo放到GitHub上,不好的地方歡迎指正出來一起交流

?閃光燈的自定義開關
?切換前后攝像頭的開關
?相機的縮放
?相機的點擊聚焦
?使用陀螺儀矯正相片的橫豎屏拍照
?拍照照片的截取處理
?添加水印制作和濾鏡功能
?Image的剪裁、縮放、旋轉等處理方法
?水印的交互處理 (拖動、刪除、放大、虛框隱藏預覽)//LHStickerView
.......

IMG_0009.PNG

一、自定義相機的準備

//首先需要引入AVFoundation 頭文件  這個框架是音視頻的框架 相機功能的API也是
#import <AVFoundation/AVFoundation.h>
//這里拍照時判斷手機的方向需要打開陀螺儀 需要這個框架
#import <CoreMotion/CoreMotion.h>

AVCaptureDevice
AVCaptureDeviceInput
AVCaptureStillImageOutput(AVCaptureOutput的子類 下文會有介紹)
AVCaptureSession (相機設備獲取數據的管理者)
AVCaptureVideoPreviewLayer

AVCaptureDevice
捕獲設備,通常是前置攝像頭,后置攝像頭,麥克風(音頻輸入)
這個類是用來管理手機設備的硬件相關的屬性和配置 在這里用來獲取前后攝像頭 (聚焦、白平衡等、閃光燈、)手電筒也會用到哦

- (AVCaptureDevice *)captureDevice
{
  if (_captureDevice == nil) {
       //使用AVMediaTypeVideo 指明self.device代表視頻,默認使用后置攝像頭進行初始  化
       _captureDevice = [AVCaptureDevice       defaultDeviceWithMediaType:AVMediaTypeVideo];
    }
    return _captureDevice;
}

詳細了解可以看這篇文章—>關于AVCaptureDevice

AVCaptureDeviceInput

設備輸入數據管理對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,該對象將會被添加到AVCaptureSession中管理
輸入數據管理對象負責從AVCaptureDevice獲取數據對象(攝像頭獲取的數據)

- (AVCaptureDeviceInput *)captureDeviceInput
{
  if (_captureDeviceInput == nil) {
  //使用設備初始化輸入
    _captureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:self.captureDevice
error:nil];
    }
    return _captureDeviceInput;
}

AVCaptureOutput

有input當然得有output了
這是一個抽象類,描述 AVCaptureSession 的結果。以下是三種關于靜態圖片捕捉的具體子類:

AVCaptureStillImageOutput 用于捕捉靜態圖片
AVCaptureMetadataOutput 啟用檢測人臉和二維碼
AVCaptureVideoDataOutput 為實時預覽圖提供原始幀

這里當然用的是AVCaptureStillImageOutput* 這個子類來獲取捕捉到的圖像描述數據了*

{
    if (_imageOutPut == nil) {
//生成輸出對象
    _imageOutPut = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *myOutputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
    [_imageOutPut setOutputSettings:myOutputSettings];
    }
    return _imageOutPut;
}

AVCaptureSession

媒體(音、視頻)捕獲會話,負責把捕獲的音視頻數據輸出到輸出設備中。一個AVCaptureSession可以有多個輸入輸出

- (AVCaptureSession *)captureSession
{
    if (_captureSession == nil) {
//生成會話,用來結合輸入輸出
    _captureSession = [[AVCaptureSession alloc]init];
    if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetPhoto]) {
//使用AVCaptureSessionPresetPhoto會自動設置為最適合的拍照配置。比如它可以允許我們使用最高的感光度 (ISO) 和曝光時間,基于相位檢測的自動對焦, 以及輸出全分辨率的 JPEG 格式壓縮的靜態圖片。
    _captureSession.sessionPreset = AVCaptureSessionPresetPhoto;
    }
    if ([_captureSession canAddInput:self.captureDeviceInput]) {
    [_captureSession addInput:self.captureDeviceInput];
    }
    if ([_captureSession canAddOutput:self.imageOutPut]) {
    [_captureSession addOutput:self.imageOutPut];
    }
}
return _captureSession;
}

這個類比較重要 蘋果一貫的方式用session來管理和橋接 包括新的ARKit 也是用ARSession來管理數據的

AVCaptureVideoPreviewLayer

CALayer的子類,可被用于自動顯示相機產生的實時圖像。它還有幾個工具性質的方法,可將 layer 上的坐標轉化到設備上。它看起來像輸出,但其實不是。另外,它擁有session (outputs 被 session所擁有)。
寫到這個類的時候就是相機該出現的時候了 創建好之后add到你的View上就可以顯示出來了

- (AVCaptureVideoPreviewLayer *)capturePreviewLayer
{
    if (_capturePreviewLayer == nil) {
    _capturePreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
    _capturePreviewLayer.backgroundColor = [UIColor blackColor].CGColor;
    CGRect layerRect = [[self layer] bounds];
    [_capturePreviewLayer setBounds:layerRect];
    [_capturePreviewLayer setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
    _capturePreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    }
    return _capturePreviewLayer;
}

二、代碼功能實現

1 . AVCaptureDevice是用來控制硬件的接口。在拍照的時候我們需要一個攝像頭的設備。因此我們需要遍歷所有設備找到相應的攝像頭。

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for ( AVCaptureDevice *device in devices )
if ( device.position == position ) return device;
return nil;
}

2. 設置并添加相機 開始啟動

- (void)customCamera{
        
    [self.layer addSublayer:self.capturePreviewLayer];

    if ([self.captureDevice lockForConfiguration:nil]) {
        
        [self flashSwitch:self.flashState];
        //自動白平衡
        if ([self.captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
            [self.captureDevice setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
        }
        [self.captureDevice unlockForConfiguration];
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //開始啟動 一般關于相機的操作最好開一個線程去操作
        [self.captureSession startRunning];
    });
   
}

**3. 給View上添加tap來實現相機的聚焦框 **

#pragma mark -- 聚焦框
- (void)focusGesture:(UITapGestureRecognizer*)gesture{
    CGPoint point = [gesture locationInView:gesture.view];
    [self focusAtPoint:point];
}
- (void)focusAtPoint:(CGPoint)point{
    
    CGSize size = self.bounds.size;
    CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );
    NSError *error;
    if ([self.captureDevice lockForConfiguration:&error]) {
        
        if ([self.captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.captureDevice setFocusPointOfInterest:focusPoint];
            [self.captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        
        if ([self.captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose ]) {
            [self.captureDevice setExposurePointOfInterest:focusPoint];
            [self.captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];
        }
        
        [self.captureDevice unlockForConfiguration];
        self.focusView.center = point;
        self.focusView.hidden = NO;
        
        [UIView animateWithDuration:0.3 animations:^{
            self.focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);
        }completion:^(BOOL finished) {
            [UIView animateWithDuration:0.5 animations:^{
                self.focusView.transform = CGAffineTransformIdentity;
            } completion:^(BOOL finished) {
                self.focusView.hidden = YES;
            }];
        }];
    }
    
}

4.攝像頭的配置
閃光燈開關功能

#pragma mark -- 閃光燈開關
- (void)flashSwitch:(LHCaptureViewFlashSwitch)switchModel{
    AVCaptureFlashMode flashModel = (AVCaptureFlashMode)switchModel;
    if ([self.captureDevice lockForConfiguration:nil]) {
        
        if ([self.captureDevice isFlashModeSupported:flashModel]) {
            [self.captureDevice setFlashMode:flashModel];
        }
        [self.captureDevice unlockForConfiguration];
    }
}

切換前后攝像頭

#pragma mark -- 改變前后攝像頭
- (void)changeCamera{
    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
    if (cameraCount > 1) {
        NSError *error;
        
        CATransition *animation = [CATransition animation];
        animation.duration = .5f;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        animation.type = @"oglFlip";
        
        AVCaptureDevice *newCamera = nil;
        AVCaptureDeviceInput *newInput = nil;
        AVCaptureDevicePosition position = [[self.captureDeviceInput device] position];
        if (position == AVCaptureDevicePositionFront){
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
            animation.subtype = kCATransitionFromLeft;
        }
        else {
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
            animation.subtype = kCATransitionFromRight;
        }
        
        newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
        [self.capturePreviewLayer addAnimation:animation forKey:nil];
        if (newInput != nil) {
            
            [self.captureSession beginConfiguration];
            [self.captureSession removeInput:self.captureDeviceInput];
            if ([self.captureSession canAddInput:newInput]) {
                [self.captureSession addInput:newInput];
                self.captureDeviceInput = newInput;
                
            } else {
                [self.captureSession addInput:self.captureDeviceInput];
            }
            
            [self.captureSession commitConfiguration];
            
        } else if (error) {
            NSLog(@"toggle carema failed, error = %@", error);
        }
        
    }
}

5. 最重要的拍照 原理應該是截取輸入幀的當前幀作為一張JPG 做了旋轉矯正等處理

#pragma mark - 拍照 截取照片
- (void)shutterCamera
{
    AVCaptureConnection * videoConnection = [self.imageOutPut connectionWithMediaType:AVMediaTypeVideo];
    if (!videoConnection) {
        NSLog(@"take photo failed!");
        return;
    }

    [videoConnection setVideoScaleAndCropFactor:_effectiveScale];

    __weak typeof(self) weakSelf = self;
    [self.imageOutPut captureStillImageAsynchronouslyFromConnection:videoConnection
                                                  completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer == NULL) {
            return;
        }
        NSData * imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        
        UIImage *originImage = [[UIImage alloc] initWithData:imageData];
        CGSize size = CGSizeMake(weakSelf.capturePreviewLayer.bounds.size.width * 2,
                                 weakSelf.capturePreviewLayer.bounds.size.height * 2);
        
        UIImage *scaledImage = [originImage resizedImageWithContentMode:UIViewContentModeScaleAspectFill
                                                                 bounds:size
                                                   interpolationQuality:kCGInterpolationHigh];
        
        CGRect cropFrame = CGRectMake((scaledImage.size.width - size.width) / 2,
                                      (scaledImage.size.height - size.height) / 2,
                                      size.width, size.height);
        UIImage *croppedImage = nil;
        if (weakSelf.captureDeviceInput.device.position == AVCaptureDevicePositionFront) {
            croppedImage = [scaledImage croppedImage:cropFrame
                                     WithOrientation:UIImageOrientationUpMirrored];
        }else
        {
            croppedImage = [scaledImage croppedImage:cropFrame];
        }
        //橫屏時旋轉image
        croppedImage = [croppedImage changeImageWithOrientation:_orientation];
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(shutterCameraWithImage:)]) {
            [weakSelf.delegate shutterCameraWithImage:croppedImage];
        }
    }];
}

6. 保存到相冊

#pragma - 保存至相冊
+ (void)saveImageToPhotoAlbum:(UIImage*)savedImage
{
UIImageWriteToSavedPhotosAlbum(savedImage, self, nil, NULL);
}

三、圖片處理(剪裁旋轉、添加水印、系統提供的濾鏡、添加文字等)

添加水印效果 ?紫霞Cosplay

添加水印核心方法

這個方法我在項目中并沒有使用 使用的是一種更粗暴的方式 圖片和水印logo 在同一個View上 所以直接截取整個View作為一個Image 截取的時候修正一些分辨率的屬性就行

/**
 *  同上
 *
 *  @param str     需要添加水印的文字
 *  @param strRect 文字的位置大小
 *  @param attri   富文本屬性
 *  @param image   水印logo
 *  @param imgRect 圖片的位置大小
 *  @param alpha   透明度
 *
 *  @return 同上
 */
- (UIImage*)imageWaterMarkWithString:(NSString*)str rect:(CGRect)strRect attribute:(NSDictionary *)attri image:(UIImage *)image imageRect:(CGRect)imgRect alpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContext(self.size);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
    if (image) {
        [image drawInRect:imgRect blendMode:kCGBlendModeNormal alpha:alpha];
    }
    
    if (str) {
        [str drawInRect:strRect withAttributes:attri];
    }
    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImage;
}
-(UIImage *)waterWithWaterImage:(UIImage *)waterImage
                      waterSize:(CGSize)waterSize
                       marginXY:(CGPoint)marginXY{
    
    CGSize size = self.size;
    
    CGRect rect = (CGRect){CGPointZero,size};
    
    //新建圖片圖形上下文
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    
    //繪制圖片
    [self drawInRect:rect];
    
    //計算水印的rect
    CGSize waterImageSize = CGSizeEqualToSize(waterSize, CGSizeZero)?waterImage.size:waterSize;
    
    //繪制水印圖片
    [waterImage drawInRect:CGRectMake(marginXY.x, marginXY.y, waterImageSize.width, waterImageSize.height)];
    
    //獲取圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    //結束圖片圖形上下文
    UIGraphicsEndImageContext();
    
    return newImage;
}

添加濾鏡

濾鏡(黑白) ?不知火舞cosplay

UIImage+Filter 這個類別負責對image進行濾鏡處理
用例中列出了系統支持的濾鏡類型

//------------濾鏡--------------------\\

// 懷舊 --> CIPhotoEffectInstant                         單色 --> CIPhotoEffectMono
// 黑白 --> CIPhotoEffectNoir                            褪色 --> CIPhotoEffectFade
// 色調 --> CIPhotoEffectTonal                           沖印 --> CIPhotoEffectProcess
// 歲月 --> CIPhotoEffectTransfer                        鉻黃 --> CIPhotoEffectChrome
// CILinearToSRGBToneCurve, CISRGBToneCurveToLinear, CIGaussianBlur, CIBoxBlur, CIDiscBlur, CISepiaTone, CIDepthOfField
/**對圖片進行濾鏡處理*/
+ (UIImage *)filterWithOriginalImage:(UIImage *)image filterName:(NSString *)name{
    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage *inputImage = [[CIImage alloc] initWithImage:image];
    CIFilter *filter = [CIFilter filterWithName:name];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    CIImage *result = [filter valueForKey:kCIOutputImageKey];
    CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
    UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    return resultImage;
}

截取當前View作為一個Image 可以保存到相冊

UIImage+Resize 項目中這個category負責處理image的size (剪切、旋轉、縮放、方向...)

+ (UIImage *)croppedImageFromView:(UIView *)theView
{
    CGSize orgSize = theView.bounds.size ;
    UIGraphicsBeginImageContextWithOptions(orgSize, YES, theView.layer.contentsScale * 3);
    [theView.layer renderInContext:UIGraphicsGetCurrentContext()]   ;
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext()    ;
    UIGraphicsEndImageContext() ;
    
    return image ;
}

用前置攝像頭拍出來的照片發現左右不對,這時候就需要這個方法來調整一下(方向對稱)

typedef NS_ENUM(NSInteger, UIImageOrientation) {
    UIImageOrientationUp,            // default orientation
    UIImageOrientationDown,          // 180 deg rotation
    UIImageOrientationLeft,          // 90 deg CCW
    UIImageOrientationRight,         // 90 deg CW
    UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip
    UIImageOrientationDownMirrored,  // horizontal flip
    UIImageOrientationLeftMirrored,  // vertical flip
    UIImageOrientationRightMirrored, // vertical flip
};
//上面的type是Image支持的方向類型 前置攝像頭 我會使用UIImageOrientationUpMirrored
- (UIImage *)croppedImage:(CGRect)bounds WithOrientation:(UIImageOrientation)orientation
{
    CGImageRef croppedCGImage = CGImageCreateWithImageInRect(self.CGImage ,bounds);
    UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImage scale:1.0f orientation:orientation];
    CGImageRelease(croppedCGImage);
    
    return croppedImage;
}

旋轉圖片

- (UIImage *)changeImageWithOrientation:(UIDeviceOrientation)deviceOrientation
{
    if (deviceOrientation != UIDeviceOrientationPortrait) {
        CGFloat degree = 0;
        switch (deviceOrientation) {
            case UIDeviceOrientationPortraitUpsideDown:
                degree = 180;//M_PI
                break;
            case UIDeviceOrientationLandscapeLeft:{
                if (self.imageOrientation == UIImageOrientationUpMirrored) {
                    degree = 90;
                }else
                    degree = - 90;//-M_PI_2
            }
                break;
            case UIDeviceOrientationLandscapeRight:{
                if (self.imageOrientation == UIImageOrientationUpMirrored) {
                    degree = - 90;
                }else
                    degree = 90;//M_PI_2
            }
                break;
            default:
                break;
        }
    return  [self rotatedByDegrees:degree];

    }
    return self;
}

- (UIImage *)rotatedByDegrees:(CGFloat)degrees
{
    // calculate the size of the rotated view's containing box for our drawing space
    UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
    CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
    rotatedViewBox.transform = t;
    CGSize rotatedSize = rotatedViewBox.frame.size;
    
    // Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();
    
    // Move the origin to the middle of the image so we will rotate and scale around the center.
    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
    
    //   // Rotate the image context
    CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
    
    // Now, draw the rotated/scaled image into the context
    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
    
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
    
    
}

開啟陀螺儀獲取當前設備方向

需求是拍照的時候要處理橫豎屏 一般有兩個方式來做
?簡單的就是設備手機的旋轉鎖屏是打開的&你的APP支持橫豎屏(如下圖),限制太多
?我這里使用陀螺儀的監測來處理翻轉方向

屏幕快照 2017-08-03 上午11.21.42.png
- (CMMotionManager *)cmmotionManager
{
    if (_cmmotionManager == nil) {
        _cmmotionManager = [[CMMotionManager alloc]init];
    }
    return _cmmotionManager;
}

- (void)startAccelerometerUpdates
{
    
    if([self.cmmotionManager isDeviceMotionAvailable]) {

       __weak typeof(self) weakSelf = self;
        
        [self.cmmotionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
            
            CGFloat xx = accelerometerData.acceleration.x;
            CGFloat yy = -accelerometerData.acceleration.y;
            CGFloat zz = accelerometerData.acceleration.z;
            CGFloat device_angle = M_PI / 2.0f - atan2(yy, xx);
            
            if (device_angle > M_PI){
                device_angle -= 2 * M_PI;
            }
            
            if ((zz < -.60f) || (zz > .60f)) {
                weakSelf.orientation = UIDeviceOrientationUnknown;
            }else{
                if ( (device_angle > -M_PI_4) && (device_angle < M_PI_4) ){
                    weakSelf.orientation = UIDeviceOrientationPortrait;
                }
                else if ((device_angle < -M_PI_4) && (device_angle > -3 * M_PI_4)){
                    weakSelf.orientation = UIDeviceOrientationLandscapeLeft;
                }
                else if ((device_angle > M_PI_4) && (device_angle < 3 * M_PI_4)){
                    weakSelf.orientation = UIDeviceOrientationLandscapeRight;
                }
                else{
                    weakSelf.orientation = UIDeviceOrientationPortraitUpsideDown;
                }
            }
            //NSLog(@"============= %f %ld",device_angle,(long)weakSelf.orientation);
        }];

    }
}
橫屏效果

Demo地址

終于有時間整理了一下 功能齊全

相機被我抽象成了一個LHCaptureView 只使用相機的話很方便 只需要添加到你的View上就可以了 接口都有注釋 易理解

幫到你了可以給個star哦 關注我哈~

LHCamera

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容