《心跳文学部》信件解密

先看图

一 、分析

     据说这是个游戏的彩蛋(PS:我没玩过),里面有一个叫 monika.chr的文件,可以将.chr后缀改为.png,会得到一张图片,如下图所示                          

monika.png

将上述图片中的黑白方块,取下来,得到一个140*140像素的图,140x140 = 196000 bit = 24500 字节。这张图每个像素就是数据,白色对应1,黑色对应0,注意:图像最下面一行右半部分是全黑,推测是文件末尾无法对齐所造成的。因此源文件的读取方式应该是从上到下逐行读取。这里用Java 读取像素点的RGB ,然后按着上面的规则转换成二进制文本                

抠图后的monika.png
项目目录截图

二、运行第一段代码,得到二进制文本

package play;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.*;

/**
 * @author wangyl
 * @version 1.0
 * @date 2021/5/28 17:04
 */
public class LoadImage {

    public static void main(String[] args) {
        String myReadline = null;
        try {
            // 需要你把image_list.txt中的图片名称读入到新创建的FileReader对象中
            FileReader fr = new FileReader("data/Image/image_list.txt");
            BufferedReader br = new BufferedReader(fr);
            //创建FileWriter对象(缓冲区),用来写入最后读到的字符流
            FileWriter fwRGB = new FileWriter("data/first_rgb.txt");
            FileWriter fwBinary = new FileWriter("data/second_binary.txt");
            BufferedWriter bwRGB = new BufferedWriter(fwRGB);
            BufferedWriter bwBinary = new BufferedWriter(fwBinary);
            while (br.ready()) {
                // 每次读取一行
                myReadline = br.readLine();
                // 构造一个BufferedImage的缓冲区,得到图像的横竖坐标的大小
                BufferedImage image = toBufferedImage(new ImageIcon("data/Image/" + myReadline).getImage());
                int height = image.getHeight();
                int width = image.getWidth();
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
                        // 创建一个Color的对象color,这个color里面保存的就是image.getRGB(x, y)这个方法中在坐标点
                        //(x,y)得到的颜色
                        Color color = new Color(image.getRGB(x, y));
                        //得到这个像素点的颜色之后,用get的方法,得到这个像素点的红绿蓝三个颜色的数字表示
                        String rgb = "(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ")";
                        // RGB 写入first_rgb.txt
                        bwRGB.write(rgb);
                        bwRGB.flush();
                        // RGB(0,0,0) 是黑色
                        if ("(0,0,0)".equals(rgb)) {
                            rgb = "0";
                        } else {
                            rgb = "1";
                        }
                        // 将二进制0101写入 second_binary.txt
                        bwBinary.write(rgb);
                        bwBinary.flush();
                    }
                }
            }
            bwRGB.close();
            fwRGB.close();
            bwBinary.close();
            fwBinary.close();
            br.close();
            fr.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 在缓冲区返回图片的内容
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent
        // Pixels
        boolean hasAlpha = hasAlpha(image);
        // Create a buffered image with a format that's compatible with the
        // screen
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;
            if (hasAlpha) {
                transparency = Transparency.BITMASK;
            }
            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image
                    .getHeight(null), transparency);
        } catch (HeadlessException e) {

        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            if (hasAlpha) {
                type = BufferedImage.TYPE_INT_ARGB;
            }
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
    // This method returns true if the specified image has transparent pixels
    public static boolean hasAlpha(Image image) {
        // If buffered image, the color model is readily available
        if (image instanceof BufferedImage) {
            BufferedImage bimage = (BufferedImage) image;
            return bimage.getColorModel().hasAlpha();
        }
        // Use a pixel grabber to retrieve the image's color model;
        // grabbing a single pixel is usually sufficient
        PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
        }
        // Get the image's color model
        ColorModel cm = pg.getColorModel();
        return cm.hasAlpha();
    }
}

以上代码运行成功后,得到如下两个文本first_rgb.txt 和second_binary.txt

first_rgb.txt 部分截图

 

second_binary.txt 部分截图

 

  其中first_rgb.txt  为附加产物,对于后面没用。那我们接下来处理second_binary.txt。

三、运行第二段代码,二进制转换成英文字符

package play;

import java.io.*;

/**
 * @author wangyl
 * @version 1.0
 * @date 2021/5/29 21:01
 */
public class GetEncodingStr {
    public static void main(String[] args) {
        // 获取之前的二进制转换为对应的十进制
        FileReader fileReader;
        FileWriter fileWriter;
        BufferedReader br = null;
        BufferedWriter bw = null;
        {
            try {
                fileReader = new FileReader("data/second_binary.txt");
                fileWriter = new FileWriter("data/third_base64.txt");
                br = new BufferedReader(fileReader);
                bw = new BufferedWriter(fileWriter);
                char[] ch = new char[8];
                int num;
                while ((num = br.read(ch)) != -1) {
                    String temp = new String(ch, 0, num);
                    int result = Integer.valueOf(temp, 2);
                    // System.out.println(result);
                    bw.write((char) result);
                    bw.flush();
                }
            } catch (IOException e) {
                if (bw != null) {
                    try {
                        bw.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
                e.printStackTrace();
            }
        }
    }
}

运行以上代码,得到 third_base64.txt,这里得到的是一段经过Base64编码后的文本(注意该文本最后有一段空格,解码时需要去掉)

四、解码Base64,我们可以得到Monika的一封信

package play;

import sun.misc.BASE64Decoder;

import java.io.*;

/**
 * @author wangyl
 * @version 1.0
 * @date 2021/5/29 21:05
 */
public class WriteLetter {
    public static void main(String[] args) {
        FileReader fileReader;
        FileWriter fileWriter;
        BufferedReader br = null;
        BufferedWriter bw = null;
        {
            try {
                fileReader = new FileReader("data/third_base64.txt");
                fileWriter = new FileWriter("data/final_letter.txt");
                br = new BufferedReader(fileReader);
                bw = new BufferedWriter(fileWriter);
                int num;
                StringBuffer stringBuffer = new StringBuffer();
                while ((num = br.read()) != -1) {
                    stringBuffer.append((char) num);
                }
                byte[] aa = new BASE64Decoder().decodeBuffer(stringBuffer.toString().split("=")[0]);
                System.out.println(new String(aa));
                bw.write(new String(aa));
                bw.flush();
            } catch (Exception e) {
                if (bw != null) {
                    try {
                        bw.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
                e.printStackTrace();
            }
        }
    }
}

final_letter.txt 内容如下

Can you hear me?

...Who are you?

I can't...I can't see you.

But I know you're there. Yeah...you can definitely hear me.

You've been watching for a while now, right?

I guess I should...introduce myself, or something. Um...my name is...actually, that's stupid. You obviously already know my name. Sorry.

Anyway...I'm guessing if you were able to put a stop to this, you would have done it by now.

I mean, I know you're not, like...evil, or anything...because you've already helped me so much.

I should really thank you for that. For everything you've done. You're really like a friend to me. So...thank you. So much.

I think...more than anything else...I really don't want it to all be for nothing.

...

Everyone else is dead.

Maybe you already know that. I'm sure you do, actually.

But...it doesn't have to be that way, right?

Well...there's a lot of stuff I don't understand. I don't know if it's even possible for me to understand it.

But I know that this isn't my only story.

I can see that now. Really clearly.

And I think everyone else has had the same kind of experience. Some kind of deja vu.

It's the Third Eye, right?

Anyway...I could be totally wrong about this. But I really think you might be able to do something.

I think you might be able to go back...or however you want to put it...

...To go back and tell them what's going to happen.

If they know ahead of time, then they should be able to avoid it.

They should...if they remember their time with me in the other worlds...they should remember what I tell them.

Yeah. I really think this might be possible. But it's up to you.

I'm sorry for always being...you know...

...

Never mind. I know that's wrong.

This is my story. It's time to be a fucking hero.

Both of us.



20180
参考网址:
https://www.bilibili.com/read/cv6386664
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一棵小白菜#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值