iOS二維碼識別/二維碼生成

最近在做一個關(guān)于二維碼的組件,已發(fā)布,現(xiàn)總結(jié)下遏乔。
開發(fā)的APP所需支持的最低版本為7.0,最初的方案為掃描使用蘋果自帶的API實現(xiàn)掃一掃的功能发笔、使用ZXing識別從相冊或別人轉(zhuǎn)發(fā)的二維碼圖片盟萨。但發(fā)現(xiàn)ZXing識別從相冊中來的圖片性能很差,很多圖片識別不了了讨,且耗時較長捻激,遂使用ZBar來實現(xiàn)識別從相冊或別人轉(zhuǎn)發(fā)的二維碼圖片。
這個組件重要有三個功能前计,掃一掃識別二維碼圖片胞谭、長按圖片識別二維碼圖片和生成二維碼圖片。

掃一掃識別二維碼圖片

- (void)initCapture {
    AVCaptureDevice* inputDevice =
    [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    [inputDevice lockForConfiguration:nil];
    if ([inputDevice hasTorch]) {
        inputDevice.torchMode = AVCaptureTorchModeAuto;
    }
    [inputDevice unlockForConfiguration];
    
    AVCaptureDeviceInput *captureInput =
    [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:nil];
    
    if (!captureInput) {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
            UIAlertController *alterVC = [UIAlertController alertControllerWithTitle:@"系統(tǒng)提示" message:@"您已關(guān)閉相機使用權(quán)限男杈,請至手機“設(shè)置->隱私->相機”中打開" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];
            [alterVC addAction:confirmAction];
            [self presentViewController:alterVC animated:YES completion:nil];
            
        } else {
            UIAlertController *alterVC = [UIAlertController alertControllerWithTitle:@"系統(tǒng)提示" message:@"未能找到相機設(shè)備" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];
            [alterVC addAction:confirmAction];
            [self presentViewController:alterVC animated:YES completion:nil];
        }
        return;
    }
    
    AVCaptureMetadataOutput *captureOutput = [[AVCaptureMetadataOutput alloc] init];
    [captureOutput setMetadataObjectsDelegate:self queue:_queue];
    self.captureOutput = captureOutput;
    self.captureSession = [[AVCaptureSession alloc] init];
    [self.captureSession addInput:captureInput];
    [self.captureSession addOutput:captureOutput];
    
    CGFloat w = 1920.f;
    CGFloat h = 1080.f;
    if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]) {
        self.captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;
    } else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        self.captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
        w = 1280.f;
        h = 720.f;
    } else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
        self.captureSession.sessionPreset = AVCaptureSessionPreset640x480;
        w = 960.f;
        h = 540.f;
    }
    captureOutput.metadataObjectTypes = [captureOutput availableMetadataObjectTypes];
    CGRect bounds = [[UIScreen mainScreen] bounds];
    
    if (!self.prevLayer) {
        self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
    }
    self.prevLayer.frame = bounds;
    self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    
    [self.view.layer insertSublayer:self.prevLayer atIndex:0];
    
//    計算rectOfInterest
    CGFloat p1 = bounds.size.height/bounds.size.width;
    CGFloat p2 = w/h;
    
    CGRect cropRect = CGRectMake(CGRectGetMinX(_cropRect) - kQRReaderScanExpandWidth, CGRectGetMinY(_cropRect) - kQRReaderScanExpandHeight, CGRectGetWidth(_cropRect) + 2*kQRReaderScanExpandWidth, CGRectGetHeight(_cropRect) + 2*kQRReaderScanExpandHeight);
    
    if (fabs(p1 - p2) < 0.00001) {
        captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y /bounds.size.height,
                                                  cropRect.origin.x/bounds.size.width,
                                                  cropRect.size.height/bounds.size.height,
                                                  cropRect.size.width/bounds.size.width);
    } else if (p1 < p2) {
        //實際圖像被截取一段高
        CGFloat fixHeight = bounds.size.width * w / h;
        CGFloat fixPadding = (fixHeight - bounds.size.height)/2;
        captureOutput.rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight,
                                                  cropRect.origin.x/bounds.size.width,
                                                  cropRect.size.height/fixHeight,
                                                  cropRect.size.width/bounds.size.width);
    } else {
        CGFloat fixWidth = bounds.size.height * h / w;
        CGFloat fixPadding = (fixWidth - bounds.size.width)/2;
        captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/bounds.size.height,
                                                  (cropRect.origin.x + fixPadding)/fixWidth,
                                                  cropRect.size.height/bounds.size.height,
                                                  cropRect.size.width/fixWidth);
    }
}

長按圖片識別二維碼圖片

識別圖片使用的是ZBar丈屹,最初的方案為ZXing,因為ZXing有人在維護伶棒,但ZXing識別相冊中的二維碼圖片或本地的圖片旺垒,有些圖片根本就識別不出來,且耗時較長肤无,所以改為使用ZBar袖牙。在網(wǎng)上找到一篇文章再見ZXing 使用系統(tǒng)原生代碼處理QRCode,實測發(fā)現(xiàn)在iOS9,iphone4s上傳回來的數(shù)組為空舅锄。代碼如下:

    //decode
    - (NSString *)decodeQRImageWith:(UIImage*)aImage {
        NSString *qrResult = nil;
        
        //iOS8及以上可以使用系統(tǒng)自帶的識別二維碼圖片接口鞭达,但此api有問題,在一些機型上detector為nil皇忿。
        
        //    if (iOS8_OR_LATER) {
        //        CIContext *context = [CIContext contextWithOptions:nil];
        //        CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
        //        CIImage *image = [CIImage imageWithCGImage:aImage.CGImage];
        //        NSArray *features = [detector featuresInImage:image];
        //        CIQRCodeFeature *feature = [features firstObject];
        //
        //        qrResult = feature.messageString;
        //    } else {
        
        ZBarReaderController* read = [ZBarReaderController new];
        CGImageRef cgImageRef = aImage.CGImage;
        ZBarSymbol* symbol = nil;
        for(symbol in [read scanImage:cgImageRef]) break;
        qrResult = symbol.data ;
        return qrResult;
    }

無圖無真相:

14567CBE-E1D2-4FA7-AFA3-8B2037171F38.jpg

detector的值為nil畴蹭,也就是說

    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];

CIDetector的初始化方法無效。推測是蘋果API的問題鳍烁。

生成二維碼圖片

在iOS8及以上版本使用蘋果的API生成二維碼圖片叨襟,代碼如下:

- (UIImage *)encodeQRImageWithContent:(NSString *)content size:(CGSize)size {
    UIImage *codeImage = nil;
    if (iOS8_OR_LATER) {
        NSData *stringData = [content dataUsingEncoding: NSUTF8StringEncoding];
       
        //生成
        CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        [qrFilter setValue:stringData forKey:@"inputMessage"];
        [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"];
        
        UIColor *onColor = [UIColor blackColor];
        UIColor *offColor = [UIColor whiteColor];
        
        //上色
        CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
                                           keysAndValues:
                                 @"inputImage",qrFilter.outputImage,
                                 @"inputColor0",[CIColor colorWithCGColor:onColor.CGColor],
                                 @"inputColor1",[CIColor colorWithCGColor:offColor.CGColor],
                                 nil];
        
        CIImage *qrImage = colorFilter.outputImage;
        CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
        UIGraphicsBeginImageContext(size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetInterpolationQuality(context, kCGInterpolationNone);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
        codeImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        CGImageRelease(cgImage);
    } else {
        codeImage = [QRCodeGenerator qrImageForString:content imageSize:size.width];
    }
    return codeImage;
}

iOS8以下使用libqrencode庫來生成二維碼圖片。

代碼完善

2015年12月11日

QA測試發(fā)現(xiàn)幔荒,服務(wù)端生成的二維碼糊闽,使用ZBar識別不出來,但將這張圖片保存到相冊爹梁,然后發(fā)送就可以識別出來右犹。最初的想法是要服務(wù)端修改生成的二維碼,但安卓能夠識別出來姚垃,此路不通念链,那只有看ZBar的源碼了。

- (id <NSFastEnumeration>) scanImage: (CGImageRef) image
{
    timer_start;
    int nsyms = [self scanImage: image
                      withScaling: 0];
  //沒有識別出來,判斷CGImageRef對象的寬和高是否大于640掂墓,大于或等于的話進行縮放再進行掃描
    if(!nsyms &&
       CGImageGetWidth(image) >= 640 &&
       CGImageGetHeight(image) >= 640)
        // make one more attempt for close up, grainy images
        nsyms = [self scanImage: image
                      withScaling: .5];

    NSMutableArray *syms = nil;
    if(nsyms) {
        // quality/type filtering
        int max_quality = MIN_QUALITY;
        for(ZBarSymbol *sym in scanner.results) {
            zbar_symbol_type_t type = sym.type;
            int quality;
            if(type == ZBAR_QRCODE)
                quality = INT_MAX;
            else
                quality = sym.quality;

            if(quality < max_quality) {
                zlog(@"    type=%d quality=%d < %d\n",
                     type, quality, max_quality);
                continue;
            }

            if(max_quality < quality) {
                max_quality = quality;
                if(syms)
                    [syms removeAllObjects];
            }
            zlog(@"    type=%d quality=%d\n", type, quality);
            if(!syms)
                syms = [NSMutableArray arrayWithCapacity: 1];

            [syms addObject: sym];
        }
    }

    zlog(@"read %d filtered symbols in %gs total\n",
          (!syms) ? 0 : [syms count], timer_elapsed(t_start, timer_now()));
    return(syms);
}

在這里就產(chǎn)生了一個解決有些二維碼圖片識別不出來的解決思路:將傳過來的UIImage的寬和高設(shè)置為640谦纱,識別不出來再進行縮放識別。修改UIImage的代碼如下:

-(UIImage *)TransformtoSize:(CGSize)Newsize
{
    // 創(chuàng)建一個bitmap的context
    UIGraphicsBeginImageContext(Newsize);
    // 繪制改變大小的圖片
    [self drawInRect:CGRectMake(0, 0, Newsize.width, Newsize.height)];
    // 從當(dāng)前context中創(chuàng)建一個改變大小后的圖片
    UIImage *TransformedImg=UIGraphicsGetImageFromCurrentImageContext();
    // 使當(dāng)前的context出堆棧
    UIGraphicsEndImageContext();
    // 返回新的改變大小后的圖片
    return TransformedImg;
}

這樣類似于ZXing中的tryHard設(shè)置為YES君编。識別不出來的二維碼圖片就可以識別了跨嘉。

2016年5月20日
bug: 點擊進入掃一掃界面,退出吃嘿,再進入祠乃,這樣重復(fù)5次左右,掃一掃之前的界面的會出現(xiàn)卡頓唠椭。
原因:多次進入掃一掃界面,再退出忍饰,因此界面未被系統(tǒng)回收贪嫂,captureSession對象一直在運行,會造成內(nèi)存泄露艾蓝,引起上一個界面卡頓力崇。
解決方案:在視圖將要消失的時候,確保captureSession對象停止運行赢织。

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self.captureSession isRunning]) {
        [self.captureSession stopRunning];
    }
}

2018年4月28日
識別二維碼圖片優(yōu)化

近期通過bugly收集卡頓問題發(fā)現(xiàn)亮靴,二維碼組件在識別二維碼圖片時,會出現(xiàn)卡頓問題于置。為優(yōu)化識別速度茧吊,采用了三種方案,并分別進行測試八毯,并對測試數(shù)據(jù)進行分析搓侄,最終挑選出最優(yōu)的方案。

任務(wù)A:使用系統(tǒng)提供的CoreImage的CIDetector接口去識別二維碼圖片话速,返回對應(yīng)的字符串讶踪;
任務(wù)B:使用zbar中的方法去識別二維碼圖片,返回對應(yīng)的字符串泊交。

//任務(wù)A
+ (NSString *)useSystemMethodDecodeImage:(UIImage *)image {
    NSString *resultString = nil;
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode
                                              context:nil
                                              options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
    if (detector) {
        CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
        NSArray *features = [detector featuresInImage:ciImage];
        CIQRCodeFeature *feature = [features firstObject];
        resultString = feature.messageString;
    }
    return resultString;
}
//任務(wù)B
+ (NSString *)useZbarMethodDecodeImage:(UIImage *)image {
    UIImage *decodeImage = image;
    if (decodeImage.size.width < 641) {
        decodeImage = [decodeImage TransformtoSize:CGSizeMake(640, 640)];
    }
    QRCodeZBarReaderController* read = [QRCodeZBarReaderController new];
    CGImageRef cgImageRef = decodeImage.CGImage;
    QRCodeZBarSymbol *symbol = nil;
    for(symbol in [read scanImage:cgImageRef]) break;
    return symbol.data;
}
  • 方案A:先執(zhí)行任務(wù)A,如果獲取到的字符串為空,再執(zhí)行任務(wù)B辱志。
+ (NSString *)planOneDecodeWithImage:(UIImage *)image index:(NSInteger)index{
 
    NSMutableString *costTimeInfo = [NSMutableString stringWithFormat:@"%ld\r\n",index];
    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
    NSString *detectorString = [MUIQRCodeDecoder useSystemMethodDecodeImage:image];
    CFAbsoluteTime detectorCostTime = (CFAbsoluteTimeGetCurrent() - startTime);
    
    [costTimeInfo appendString:[NSString stringWithFormat:@"detector : %f ms\r\n",detectorCostTime *1000.0]];
    
    NSAssert(detectorString.length > 0, @"detector fail!");
    CFAbsoluteTime zbarStartTime = CFAbsoluteTimeGetCurrent();
    NSString *zbarSymbolString = [MUIQRCodeDecoder useZbarMethodDecodeImage:image];
    NSAssert(zbarSymbolString.length > 0, @"zbar fail!");
    CFAbsoluteTime zbarCostTime = (CFAbsoluteTimeGetCurrent() - zbarStartTime);
    
    [costTimeInfo appendString:[NSString stringWithFormat:@"zbar : %f ms\r\n",zbarCostTime *1000.0]];
    
    CFAbsoluteTime totalCostTime = (CFAbsoluteTimeGetCurrent() - startTime);
    
    [costTimeInfo appendString:[NSString stringWithFormat:@"total cost : %f ms\r\n",totalCostTime *1000.0]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"detectorString : %@ ms\r\n",detectorString]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"zbarSymbolString : %@ ms\r\n",zbarSymbolString]];
    return [costTimeInfo copy];
}
  • 方案B:同時執(zhí)行任務(wù)A和任務(wù)B比庄,兩者均執(zhí)行完后,返回識別的結(jié)果研乒;
+ (NSString *)planTwoDecodeWithImage:(UIImage *)image index:(NSInteger)index { 
    __block NSMutableString *costTimeInfo = [NSMutableString stringWithFormat:@"%ld\r\n",index];
    __block NSString *detectorString = nil;
    __block NSString *zbarSymbolString = nil;
    
    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        detectorString = [MUIQRCodeDecoder useSystemMethodDecodeImage:image];
        NSAssert(detectorString.length > 0, @"detector fail!");
        CFAbsoluteTime costTime = (CFAbsoluteTimeGetCurrent() - startTime);
        [costTimeInfo appendString:[NSString stringWithFormat:@"detector : %f ms\r\n",costTime *1000.0]];
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        zbarSymbolString = [MUIQRCodeDecoder useZbarMethodDecodeImage:image];
        NSAssert(zbarSymbolString.length > 0, @"zbar fail!");
        CFAbsoluteTime costTime = (CFAbsoluteTimeGetCurrent() - startTime);
        [costTimeInfo appendString:[NSString stringWithFormat:@"zbar : %f ms\r\n",costTime *1000.0]];
    });
    
    dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
        dispatch_semaphore_signal(semaphore);
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    CFAbsoluteTime totalCostTime = (CFAbsoluteTimeGetCurrent() - startTime);
    [costTimeInfo appendString:[NSString stringWithFormat:@"total cost : %f ms\r\n",totalCostTime *1000.0]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"detectorString : %@ ms\r\n",detectorString]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"zbarSymbolString : %@ ms\r\n",zbarSymbolString]];
    return [costTimeInfo copy];
}
  • 方案C:同時執(zhí)行任務(wù)A和任務(wù)B
    1留晚、任務(wù)A先執(zhí)行完且識別成功,返回識別結(jié)果;
    2错维、任務(wù)B先執(zhí)行完且識別成功奖地,返回識別結(jié)果;
    3赋焕、任務(wù)A和任務(wù)B均識別失敗参歹,兩者均執(zhí)行完后,返回識別的結(jié)果隆判。
+ (NSString *)planThreeDecodeWithImage:(UIImage *)image index:(NSInteger)index {
    __block NSMutableString *costTimeInfo = [NSMutableString stringWithFormat:@"%ld\r\n",index];
    __block NSString *detectorString = nil;
    __block NSString *zbarSymbolString = nil;
    __block BOOL isNeedSendSignal = YES;
    
    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        detectorString = [MUIQRCodeDecoder useSystemMethodDecodeImage:image];
        //NSAssert(detectorString.length > 0, @"detector fail!");
        CFAbsoluteTime costTime = (CFAbsoluteTimeGetCurrent() - startTime);
        [costTimeInfo appendString:[NSString stringWithFormat:@"detector : %f ms\r\n",costTime *1000.0]];
        if (detectorString.length > 0 && isNeedSendSignal) {
            isNeedSendSignal = NO;
            dispatch_semaphore_signal(semaphore);
        }
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        zbarSymbolString = [MUIQRCodeDecoder useZbarMethodDecodeImage:image];
        //NSAssert(zbarSymbolString.length > 0, @"zbar fail!");
        CFAbsoluteTime costTime = (CFAbsoluteTimeGetCurrent() - startTime);
        [costTimeInfo appendString:[NSString stringWithFormat:@"zbar : %f ms\r\n",costTime *1000.0]];
        if (zbarSymbolString.length > 0 && isNeedSendSignal) {
            isNeedSendSignal = NO;
            dispatch_semaphore_signal(semaphore);
        }
    });
    
    dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
        if (isNeedSendSignal) {
            dispatch_semaphore_signal(semaphore);
        }
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    CFAbsoluteTime totalCostTime = (CFAbsoluteTimeGetCurrent() - startTime);
    [costTimeInfo appendString:[NSString stringWithFormat:@"total cost : %f ms\r\n",totalCostTime *1000.0]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"detectorString : %@ ms\r\n",detectorString]];
    [costTimeInfo appendString:[NSString stringWithFormat:@"zbarSymbolString : %@ ms\r\n",zbarSymbolString]]; 
    return [costTimeInfo copy];
}

測試數(shù)據(jù)如下所示:(取了前10張圖片)

識別二維碼圖片耗時.png

分析測試數(shù)據(jù)發(fā)現(xiàn):
1犬庇、在測試第一張二維碼圖片時,總耗時均較大侨嘀,如果第一次識別使用的是系統(tǒng)方法臭挽,耗時超過500ms,這也是為什么會出現(xiàn)卡頓的原因咬腕;
2欢峰、使用系統(tǒng)方法去識別二維碼圖片時,如果不是第一次去識別涨共,耗時較小纽帖,在65ms以內(nèi);
3举反、使用zbar的方法去識別二維碼圖片懊直,耗時均值在200ms以內(nèi);
4火鼻、在方案C中室囊,如果第一次使用系統(tǒng)方法,耗時為226ms魁索。

總結(jié)得出波俄,從優(yōu)化卡頓問題的角度出發(fā),使用方案C最優(yōu)蛾默,同時發(fā)現(xiàn)懦铺,如果使用系統(tǒng)方法能識別出二維碼圖片,在初始化之后(也就是第二次使用)支鸡,耗時最短冬念。同時因為在實際的使用場景中,圖片是一張一張識別的牧挣,識別過程有一個間隔時間急前,如果已經(jīng)使用系統(tǒng)方法識別過二維碼圖片,那下次識別就能達到最優(yōu)瀑构。所以使用方案C的話裆针,最差情況均值在200ms左右刨摩,最好的情況和方案A中第二次使用系統(tǒng)方法耗時基本一致。綜合考慮世吨,使用方案C澡刹。

小結(jié)

在實際的項目開發(fā)過程中,設(shè)想的情況和實際情況會存在偏差耘婚,需要自己時刻使用性能調(diào)優(yōu)工具罢浇,根據(jù)數(shù)據(jù)去進行優(yōu)化,而不能想當(dāng)然的認為某種方式是最優(yōu)的沐祷。
源碼和demo請點這里
參考的文章鏈接如下
再見ZXing 使用系統(tǒng)原生代碼處理QRCode
IOS二維碼掃描,你需要注意的兩件事
Zbar算法流程介紹
本文已經(jīng)同步到我的個人技術(shù)博客: 傳送門 嚷闭,歡迎常來^^。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赖临,一起剝皮案震驚了整個濱河市胞锰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兢榨,老刑警劉巖嗅榕,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異色乾,居然都是意外死亡誊册,警方通過查閱死者的電腦和手機领突,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門暖璧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人君旦,你說我怎么就攤上這事澎办。” “怎么了金砍?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵局蚀,是天一觀的道長。 經(jīng)常有香客問我恕稠,道長琅绅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任鹅巍,我火速辦了婚禮千扶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骆捧。我一直安慰自己澎羞,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布敛苇。 她就那樣靜靜地躺著妆绞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上括饶,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天株茶,我揣著相機與錄音,去河邊找鬼巷帝。 笑死忌卤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的楞泼。 我是一名探鬼主播驰徊,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼堕阔!你這毒婦竟也來了棍厂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤超陆,失蹤者是張志新(化名)和其女友劉穎牺弹,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體时呀,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡张漂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谨娜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片航攒。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖趴梢,靈堂內(nèi)的尸體忽然破棺而出漠畜,到底是詐尸還是另有隱情,我是刑警寧澤坞靶,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布憔狞,位于F島的核電站,受9級特大地震影響彰阴,放射性物質(zhì)發(fā)生泄漏瘾敢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一尿这、第九天 我趴在偏房一處隱蔽的房頂上張望簇抵。 院中可真熱鬧,春花似錦妻味、人聲如沸正压。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焦履。三九已至拓劝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘉裤,已是汗流浹背郑临。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屑宠,地道東北人厢洞。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像典奉,于是被迫代替她去往敵國和親躺翻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

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