Luban压缩改编

单纯的compile luban 还要默认添加rxjava 如果项目里 没有用到rxjava 所以也就不用继续添加他的代码

  • 自己改编 主要修改launch方法 之前全部用rxjava 写的 现在写的AsyncTask
package org.xiaozhi.framework.util.luban;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;


import cn.bingoogolapple.qrcode.core.BGAQRCodeUtil;
import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder;

import static org.xiaozhi.framework.util.luban.Preconditions.checkNotNull;


public class Luban {
    public static int FIRST_GEAR = 1;
    public static int THIRD_GEAR = 3;

    private static final String TAG = "Luban";

    private static volatile Luban INSTANCE;

    private final File mCacheDir;

    private OnCompressListener compressListener;
    private File mFile;
    private String filename;

    private Luban(File cacheDir) {
        mCacheDir = cacheDir;
    }

    /**
     * Returns a directory with a default name in the private cache directory of the application to use to store
     * retrieved media and thumbnails.
     *
     * @param context A context.
     */
    private static synchronized File getPhotoCacheDir(Context context) {
        File cacheDir = context.getCacheDir();
        if (cacheDir != null) {
            String DEFAULT_DISK_CACHE_DIR = "luban_disk_cache";

            File result = new File(cacheDir, DEFAULT_DISK_CACHE_DIR);
            if (!result.mkdirs() && (!result.exists() || !result.isDirectory())) {
                // File wasn't able to create a directory, or the result exists but not a directory
                return null;
            }

            File noMedia = new File(cacheDir + "/.nomedia");
            if (!noMedia.mkdirs() && (!noMedia.exists() || !noMedia.isDirectory())) {
                return null;
            }

            return result;
        }
        if (Log.isLoggable(TAG, Log.ERROR)) {
            Log.e(TAG, "default disk cache dir is null");
        }
        return null;
    }

    public static Luban get(Context context) {
        if (INSTANCE == null) {
            INSTANCE = new Luban(Luban.getPhotoCacheDir(context));
        }
        return INSTANCE;
    }

    public Luban launch() {
        checkNotNull(mFile, "the image file cannot be null, please call .load() before this method!");

        if (compressListener != null) compressListener.onStart();


        if (mFile == null || !mFile.exists()) {

            if (compressListener != null) {
                compressListener.onError(new FileNotFoundException("inputFile not exists"));
            }
            return this;

        }
        if (!mFile.canRead()) {
            if (compressListener != null) {
                compressListener.onError(new IOException("inputFile is cannot read"));
            }
            return this;
        }

        new AsyncTask<Void, Void, File>() {
            @Override
            protected File doInBackground(Void... params) {
                return  Compress(mFile);
            }

            @Override
            protected void onPostExecute(File file) {
                if (file != null) {
                    if (compressListener != null) compressListener.onSuccess(file);
                } else {
                    if (compressListener != null) compressListener.onError(new Exception("压缩失败"));
                }
            }
        }.execute();

        return this;
    }

    public Luban load(File file) {
        mFile = file;
        return this;
    }

    public Luban setCompressListener(OnCompressListener listener) {
        compressListener = listener;
        return this;
    }

    /**
     * @deprecated
     */
    public Luban putGear(int gear) {
        return this;
    }

    /**
     * @deprecated
     */
    public Luban setFilename(String filename) {
        this.filename = filename;
        return this;
    }


    private File Compress(File file) {
        String thumb = mCacheDir.getAbsolutePath() + File.separator +
                (TextUtils.isEmpty(filename) ? System.currentTimeMillis() : filename) + ".jpg";

        double size;
        String filePath = file.getAbsolutePath();

        int angle = getImageSpinAngle(filePath);
        int width = getImageSize(filePath)[0];
        int height = getImageSize(filePath)[1];
        int thumbW = width % 2 == 1 ? width + 1 : width;
        int thumbH = height % 2 == 1 ? height + 1 : height;

        width = thumbW > thumbH ? thumbH : thumbW;
        height = thumbW > thumbH ? thumbW : thumbH;

        double scale = ((double) width / height);

        if (scale <= 1 && scale > 0.5625) {
            if (height < 1664) {
                if (file.length() / 1024 < 150) return file;

                size = (width * height) / Math.pow(1664, 2) * 150;
                size = size < 60 ? 60 : size;
            } else if (height >= 1664 && height < 4990) {
                thumbW = width / 2;
                thumbH = height / 2;
                size = (thumbW * thumbH) / Math.pow(2495, 2) * 300;
                size = size < 60 ? 60 : size;
            } else if (height >= 4990 && height < 10240) {
                thumbW = width / 4;
                thumbH = height / 4;
                size = (thumbW * thumbH) / Math.pow(2560, 2) * 300;
                size = size < 100 ? 100 : size;
            } else {
                int multiple = height / 1280 == 0 ? 1 : height / 1280;
                thumbW = width / multiple;
                thumbH = height / multiple;
                size = (thumbW * thumbH) / Math.pow(2560, 2) * 300;
                size = size < 100 ? 100 : size;
            }
        } else if (scale <= 0.5625 && scale > 0.5) {
            if (height < 1280 && file.length() / 1024 < 200) return file;

            int multiple = height / 1280 == 0 ? 1 : height / 1280;
            thumbW = width / multiple;
            thumbH = height / multiple;
            size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400;
            size = size < 100 ? 100 : size;
        } else {
            int multiple = (int) Math.ceil(height / (1280.0 / scale));
            thumbW = width / multiple;
            thumbH = height / multiple;
            size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500;
            size = size < 100 ? 100 : size;
        }

        return compress(filePath, thumb, thumbW, thumbH, angle, (long) size);
    }

    /**
     * obtain the image's width and height
     *
     * @param imagePath the path of image
     */
    public int[] getImageSize(String imagePath) {
        int[] res = new int[2];

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;
        BitmapFactory.decodeFile(imagePath, options);

        res[0] = options.outWidth;
        res[1] = options.outHeight;

        return res;
    }

    /**
     * obtain the thumbnail that specify the size
     *
     * @param imagePath the target image path
     * @param width     the width of thumbnail
     * @param height    the height of thumbnail
     * @return {@link Bitmap}
     */
    private Bitmap compress(String imagePath, int width, int height) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);

        int outH = options.outHeight;
        int outW = options.outWidth;
        int inSampleSize = 1;

        if (outH > height || outW > width) {
            int halfH = outH / 2;
            int halfW = outW / 2;

            while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) {
                inSampleSize *= 2;
            }
        }

        options.inSampleSize = inSampleSize;

        options.inJustDecodeBounds = false;

        int heightRatio = (int) Math.ceil(options.outHeight / (float) height);
        int widthRatio = (int) Math.ceil(options.outWidth / (float) width);

        if (heightRatio > 1 || widthRatio > 1) {
            if (heightRatio > widthRatio) {
                options.inSampleSize = heightRatio;
            } else {
                options.inSampleSize = widthRatio;
            }
        }
        options.inJustDecodeBounds = false;

        return BitmapFactory.decodeFile(imagePath, options);
    }

    /**
     * obtain the image rotation angle
     *
     * @param path path of target image
     */
    private int getImageSpinAngle(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 指定参数压缩图片
     * create the thumbnail with the true rotate angle
     *
     * @param largeImagePath the big image path
     * @param thumbFilePath  the thumbnail path
     * @param width          width of thumbnail
     * @param height         height of thumbnail
     * @param angle          rotation angle of thumbnail
     * @param size           the file size of image
     */
    private File compress(String largeImagePath, String thumbFilePath, int width, int height, int angle, long size) {
        Bitmap thbBitmap = compress(largeImagePath, width, height);

        thbBitmap = rotatingImage(angle, thbBitmap);

        return saveImage(thumbFilePath, thbBitmap, size);
    }

    /**
     * 旋转图片
     * rotate the image with specified angle
     *
     * @param angle  the angle will be rotating 旋转的角度
     * @param bitmap target image               目标图片
     */
    private static Bitmap rotatingImage(int angle, Bitmap bitmap) {
        //rotate image
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);

        //create a new image
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 保存图片到指定路径
     * Save image with specified size
     *
     * @param filePath the image file save path 储存路径
     * @param bitmap   the image what be save   目标图片
     * @param size     the file size of image   期望大小
     */
    private File saveImage(String filePath, Bitmap bitmap, long size) {
        checkNotNull(bitmap, TAG + "bitmap cannot be null");

        File result = new File(filePath.substring(0, filePath.lastIndexOf("/")));

        if (!result.exists() && !result.mkdirs()) return null;

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int options = 100;
        bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream);

        while (stream.toByteArray().length / 1024 > size && options > 6) {
            stream.reset();
            options -= 6;
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream);
        }
        bitmap.recycle();

        try {
            FileOutputStream fos = new FileOutputStream(filePath);
            fos.write(stream.toByteArray());
            fos.flush();
            fos.close();
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new File(filePath);
    }
}
  • 这是朋友修改的版本 还没来得及用
package com.bdyue.dialoguelibrary.util;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;

import com.bdyue.common.util.DisplayUtil;
import com.bdyue.common.util.ThreadPoolAsyncTask;
import com.bdyue.dialoguelibrary.interfaces.DialogueCompressListener;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 图片压缩<br/>
 * Created by cds on 2016/9/5.
 */
public class ImageCompressUtil {
    /**
     * 参考第一级最大压缩大小
     */
    private long firstMaxSize = 150;
    /**
     * 参考第二级最大压缩大小
     */
    private long secondMaxSize = 200;
    /**
     * 参考的第一级最小压缩大小
     */
    private long firstMinSize = 60;
    /**
     * 参考的第二级最小压缩大小
     */
    private long secondMinSize = 120;

    private Activity mActivity;
    private File inputFile;
    private File resultFile;
    private DialogueCompressListener listener;

    public ImageCompressUtil(Activity activity, File inputFile, File resultFile, DialogueCompressListener listener) {
        mActivity = activity;
        this.inputFile = inputFile;
        this.resultFile = resultFile;
        this.listener = listener;
    }

    public ImageCompressUtil(Activity context, File inputFile, File resultFile, DialogueCompressListener listener,
                             long firstMaxSize, long secondMaxSize, long firstMinSize, long secondMinSize) {
        mActivity = context;
        this.inputFile = inputFile;
        this.resultFile = resultFile;
        this.listener = listener;
        this.firstMaxSize = firstMaxSize;
        this.secondMaxSize = secondMaxSize;
        this.firstMinSize = firstMinSize;
        this.secondMinSize = secondMinSize;
    }

    /**
     * 开始压缩
     */
    public void start() {
        if (mActivity == null || mActivity.isFinishing()) return;
        if (listener != null) {
            listener.onStart();
        }
        if (inputFile == null || !inputFile.exists()) {
            if (listener != null) {
                listener.onError(new FileNotFoundException("inputFile not exists"));
            }
            return;
        }
        if (!inputFile.canRead()) {
            if (listener != null) {
                listener.onError(new IOException("inputFile is cannot read"));
            }
            return;
        }
        if (resultFile == null) {
            if (listener != null) {
                listener.onError(new IllegalArgumentException("inputFile is null"));
            }
            return;
        }
        new CompressTask().executeThreadPool();
    }

    /**
     * 转换图片
     */
    private class CompressTask extends ThreadPoolAsyncTask<File,File,Boolean> {

        @Override
        protected Boolean doInBackground(File[] params) {
            return compress();
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (mActivity == null || mActivity.isFinishing()) return;
            if (result) {
                if (listener != null) {
                    listener.onSuccess();
                }
            }
        }
    }

    /**
     * 进行转换
     * @return true or false
     */
    private boolean compress() {
        boolean saveSuccess;
        boolean shouldCompress;
        try {
            FileInputStream inputStream = new FileInputStream(inputFile);
            FileOutputStream resultStream = new FileOutputStream(resultFile);
            double size = firstMinSize;
            int angle = getImageSpinAngle(inputFile.getAbsolutePath());
            int[] wh = DisplayUtil.getImageWH(inputFile.getAbsolutePath());
            int shortSide = wh[0];
            int longSide = wh[1];
            int resultShort = shortSide % 2 == 1 ? shortSide + 1 : shortSide;
            int resultLong = longSide % 2 == 1 ? longSide + 1 : longSide;

            if (inputFile.length() / 1024.0f < firstMinSize){
                // 小于60Kb的图片不进行任何压缩
                shouldCompress = false;
            }else {
                shortSide = resultShort > resultLong ? resultLong : resultShort;
                longSide = resultShort > resultLong ? resultShort : resultLong;
                // 长边和小边的比例
                double scale = ((double) shortSide / longSide);
                if (scale <= 1 && scale > 0.5625) {
                    // 图片处于 [1:1 ~ 9:16) 比例范围内
                    if (longSide < 1664) {
                        if (inputFile.length() / 1024.0f < firstMaxSize) {
                            shouldCompress = false;
                        } else {
                            size = (shortSide * longSide) / Math.pow(1664, 2) * firstMaxSize;
                            size = size < firstMinSize ? firstMinSize : size;
                            shouldCompress = true;
                        }
                    } else if (longSide >= 1664 && longSide < 4990) {
                        resultShort = shortSide / 2;
                        resultLong = longSide / 2;
                        size = (resultShort * resultLong) / Math.pow(2495, 2) * 300;
                        size = size < firstMinSize ? firstMinSize : size;
                        shouldCompress = true;
                    } else if (longSide >= 4990 && longSide < 10240) {
                        resultShort = shortSide / 4;
                        resultLong = longSide / 4;
                        size = (resultShort * resultLong) / Math.pow(2560, 2) * 300;
                        size = size < secondMinSize ? secondMinSize : size;
                        shouldCompress = true;
                    } else {
                        float multiple = longSide / 1280 == 0 ? 1 : longSide / 1280.0f;
                        resultShort = (int)(shortSide / multiple);
                        resultLong = (int)(longSide / multiple);
                        size = (resultShort * resultLong) / Math.pow(2560, 2) * 300;
                        size = size < secondMinSize ? secondMinSize : size;
                        shouldCompress = true;
                    }
                } else if (scale <= 0.5625 && scale > 0.5) {
                    // 图片处于 [9:16 ~ 1:2) 比例范围内
                    if (longSide < 1280 && inputFile.length() / 1024.0f < secondMaxSize){
                        shouldCompress = false;
                    } else {
                        float multiple = longSide / 1280 == 0 ? 1 : longSide / 1280.0f;
                        resultShort = (int) (shortSide / multiple);
                        resultLong = (int) (longSide / multiple);
                        size = (resultShort * resultLong) / (1440.0 * 2560.0) * 400;
                        size = size < secondMinSize ? secondMinSize : size;
                        shouldCompress = true;
                    }
                } else {
                    // 图片处于 [1:2 ~ 1:∞) 比例范围内 小边保持在400以上
                    if (scale < (400.0 / 1280.0)){
                        // 长边是小边的3倍以上时,进行稍微压缩
                        if (shortSide <= 400) {
                            // 小边小于400时不压缩
                            shouldCompress = false;
                        } else {
                            // 小边压缩到400
                            float multiple = shortSide / 400.0f;
                            resultShort = (int)(shortSide / multiple);
                            resultLong = (int)(longSide / multiple);
                            size = inputFile.length() / 1024.0 * multiple;
                            size = size < secondMinSize ? secondMinSize : size;
                            shouldCompress = true;
                        }
                    } else {
                        // 长短比在2到3时
                        float multiple = (float) (longSide / (1280.0 / scale));
                        resultShort = (int)(shortSide / multiple);
                        resultLong = (int)(longSide / multiple);
                        size = ((resultShort * resultLong) / (1280.0 * (1280 / scale))) * 500;
                        size = size < secondMinSize ? secondMinSize : size;
                        shouldCompress = true;
                    }
                }
            }
            if (shouldCompress) {
                // 图片转换
                Bitmap resultBitmap = getBitmap(resultShort, resultLong);
                resultBitmap = rotatingImage(angle, resultBitmap);
                writeBitmap(resultBitmap, size, resultStream);
            } else {
                // 拷贝文件
                copyFile(inputStream, resultStream);
            }
            inputStream.close();
            resultStream.close();
            resultStream.flush();
            saveSuccess = true;
        } catch (Exception ex) {
            if (listener != null) {
                listener.onError(ex);
            }
            saveSuccess = false;
        }
        return saveSuccess;
    }

    /**
     * 获取bitmap
     * @param resultShort resultShort
     * @param resultLong resultLong
     */
    private Bitmap getBitmap(int resultShort, int resultLong){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(inputFile.getPath(), options);
        int outShort, outLong;
        if (options.outHeight > options.outWidth) {
            outShort = options.outWidth;
            outLong = options.outHeight;
        } else {
            outShort = options.outHeight;
            outLong = options.outWidth;
        }
        int inSampleSize = 1;

        int shortRatio = Math.round(outShort/ (float) resultShort);
        int longRatio = Math.round(outLong / (float) resultLong);

        Bitmap resultBitmap;
        boolean shouldScale = false;
        int shouldWidth = 0, shouldHeight = 0;

        if (shortRatio > 1 && longRatio > 1) {
            if (shortRatio > longRatio) {
                if (shortRatio % 2 != 0) {
                    shortRatio = shortRatio / 2;
                    shouldScale = true;
                    if (options.outHeight > options.outWidth) {
                        shouldWidth = resultShort / shortRatio;
                        shouldHeight = resultLong / shortRatio;
                    } else {
                        shouldWidth = resultLong / shortRatio;
                        shouldHeight = resultShort / shortRatio;
                    }
                }
                inSampleSize = shortRatio;
            } else {
                if (longRatio % 2 != 0) {
                    longRatio = longRatio / 2;
                    shouldScale = true;
                    if (options.outHeight > options.outWidth) {
                        shouldWidth = resultShort / longRatio;
                        shouldHeight = resultLong / longRatio;
                    } else {
                        shouldWidth = resultLong / longRatio;
                        shouldHeight = resultShort / longRatio;
                    }
                }
                inSampleSize = longRatio;
            }
        }
        options.inSampleSize = inSampleSize;
        options.inJustDecodeBounds = false;

        resultBitmap = BitmapFactory.decodeFile(inputFile.getPath(), options);
        if (shouldScale) {
            resultBitmap = Bitmap.createScaledBitmap(resultBitmap, shouldWidth, shouldHeight, false);
        }
        return resultBitmap;
    }

    /**
     * 获取当前图片的旋转角度
     * @param path 图片路径
     */
    private int getImageSpinAngle(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 读入stream,保存图片
     * @param bitmap bitmap
     * @param size size
     * @param stream stream
     */
    private void writeBitmap(Bitmap bitmap, double size, FileOutputStream stream) throws IOException{
        ByteArrayOutputStream byteArrayOs = new ByteArrayOutputStream();
        DisplayUtil.compressBitmap(bitmap, size, byteArrayOs);
        byteArrayOs.writeTo(stream);
        byteArrayOs.close();
        byteArrayOs.flush();
        bitmap.recycle();
    }

    /**
     * 旋转图片
     * @param angle  the angle will be rotating 旋转的角度
     * @param bitmap target image               目标图片
     */
    private static Bitmap rotatingImage(int angle, Bitmap bitmap) {
        //rotate image
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);

        //create a new image
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 文件保存
     * @param inputStream 输入流
     * @param outputStream 输出流
     * @throws IOException
     */
    public static void copyFile(InputStream inputStream, OutputStream outputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int byteRead;
        while ((byteRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, byteRead);
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容