需求

  • 加入保存保存快捷键ctrl+s
  • 修改代码,支持多次保存

实现

加入保存快捷键

在ScreenShotWindow.java中加入快捷键变量声明:
第1步:

1
2
// 定义保存快捷键
public static final int SaveImage_HOT_KEY = 4;

第2步:
注册快捷键:

1
2
3
//添加保存快捷键
JIntellitype.getInstance().registerHotKey(SaveImage_HOT_KEY,
JIntellitype.MOD_CONTROL, (int) 'S');

第3步:编写事件监听逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 第3步:添加热键监听器JIntellitype
JIntellitype.getInstance().addHotKeyListener(new HotkeyListener()
{
@Override
public void onHotKey(int markCode)
{
switch (markCode)
{
// 按下alt+w快捷键表示再次截屏
case SCREENSHOT_HOT_KEY :
// showMessage();
// ScreenShotOCR.visiable();
//如果当前窗口可见的话
//再次截屏时,隐藏工具窗口
if(tools!=null)
{
tools.setVisible(false);
}
//重新截屏
try
{
createScreenCapture();
} catch (AWTException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

//显示窗口
ScreenShotOCR.visiable();
// //让窗口置顶
// 这个应该在开始的时候就设置
// ScreenShotOCR.ssw.setAlwaysOnTop(true);
// tools.setAlwaysOnTop(true);
break;
// alt+q快捷键表示退出程序
case EXIT_KEY_MARK :
System.exit(0);
break;
case EXIT_SCREENSHOT_HOT_KEY:
//让窗口不显示
ScreenShotWindow.this.setVisible(false);//不显示窗口
tools.setLocation(0, 0);
break;
case SaveImage_HOT_KEY:
//让窗口不显示
ScreenShotWindow.this.setVisible(false);//不显示窗口
tools.setLocation(0, 0);
try
{
saveImage();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
});

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
case SaveImage_HOT_KEY:
//让窗口不显示
ScreenShotWindow.this.setVisible(false);//不显示窗口
tools.setLocation(0, 0);
try
{
saveImage();//按下ctrl+s时调用保存图片函数
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
break;

这样就注册了保存快捷键了。接下来修改保存函数。

支持多次保存保存后不退出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 保存图像到文件
public void saveImage() throws IOException
{

JFileChooser jfc = new JFileChooser();
jfc.setDialogTitle("保存");

// 文件过滤器,用户过滤可选择文件
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG",
"png");
jfc.setFileFilter(filter);

// 初始化一个默认文件(此文件会生成到桌面上)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
String fileName = sdf.format(new Date());
File filePath = FileSystemView.getFileSystemView().getHomeDirectory();
File defaultFile = new File(
filePath + File.separator + fileName + ".png");
jfc.setSelectedFile(defaultFile);

int flag = jfc.showSaveDialog(this);
if (flag == JFileChooser.APPROVE_OPTION)
{
File file = jfc.getSelectedFile();
String path = file.getPath();
// 检查文件后缀,放置用户忘记输入后缀或者输入不正确的后缀
if (!(path.endsWith(".png") || path.endsWith(".PNG")))
{
path += ".png";
}

// 写入文件
ImageIO.write(saveImage, "png", new File(path));
//不退出
//System.exit(0);
}
}

原先的代码中截图后就退出了,关键代码:System.exit(0);把这一段话注释掉即可。

出现问题

无法使用ctrl+s快捷键,因为JIntellitype注册的是全局快捷键,在其他软件中按下ctrl+s进行保存文档的时候,系统会误认为是调用了保存图片。这样是不对的。这里解决方法是吧保存图片快捷键改成ctrl+alt+s。局部快捷键怎么设置为还不知道。先别管他,能用就行了,我先去学点其他东西。

写到HTML这章的时候,在Markdown中添加了好多html标记,这样会引起文章渲染乱码。所以需要都让对一些HTML标记进行”转义”。我这里的做法是,使用反引号把HTML标记包裹起来。如下所示:

1
`<h1>`

这样渲染的时候就以代码的方式渲染,而不是渲染为HTML标记。我写文章用的是MarkdownPad2,因为MarkdownPad2的快捷键很好用。不过MarkdownPad2好像只支持正则表达查找,不能替换,更不支持正则表达式替换。后来发现NotePad++支持正则表达式替换
所以,就用NotePad++来完成正则表达式替换功能

匹配HTML标签的正则表达式:(</?[a-zA_Z]*>)
在这个HTML标签两边加上反引号”转义”:

1
`\1`

这里使用括号捕获这个HTML标签。然后使用反向引用\1即可引用到这个刚匹配的文本,用反引号包裹起来,替换掉原来的文本即可实现我的要求。
具体设置如下图所示:
https://image-1257720033.cos.ap-shanghai.myqcloud.com/blog/Java%20Web%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/2/Notepad%2B%2B%E6%AD%A3%E5%88%99%E6%9B%BF%E6%8D%A2.png
最后,说一下,NotePad++打开替换的快捷键是:ctrl+H。当然,这个正则表达式并不严谨,但是对我来说已经够用了。

在使用GUI中的组件进行窗体的设计时,当需要将窗体始终显示在屏幕的某一位置时,例如屏幕的中央。由于不同的电脑屏幕分辨率是不同的,所以在进行处理时会有一定的难度,还有就是当我们需要修改窗体的图标时,这些都要用到Tookit工具包。
首先,为了解决窗体的显示问题,进行如下设置:

1
2
3
4
5
Toolkit toolkit = getToolkit();// 获得窗体工具包
Dimension screenSize = toolkit.getScreenSize();// 获取屏幕大小
int width = (int) (screenSize.width * 0.8);// 计算窗体新宽度
int height = (int) (screenSize.height * 0.8);// 计算窗体新宽度
setSize(width, height);// 设置窗体大小

之前已经完成了程序的开发,也加入了热键,不过每次截图(ctrl+alt+w)都要手动的去点击文字识别按钮,显然有点浪费时间。
需求,添加文字识别快捷键(alt+B(BaiduOCR的简称))

实现,支持快捷键即可。

需求

让工具栏在截图窗口消失的时候,显示在屏幕左上角,避免挡住屏幕影响阅读。
在构造函数中传入工具栏窗口的引用tools,然后嗲用tools.setLocation(0,0)。即可,本来我想着放在右边的,但是放右边的话不好计算坐标,索性就放右上角。
添加构造函数:

1
2
3
4
5
6
7
8
public BaiduOCR(String path, ScreenShotWindow screenShotWindow,
JButton baiduOCRButton, ToolsWindow tools)
{
this.path = path;
this.screenShotWindow = screenShotWindow;
this.baiduOCRButton = baiduOCRButton;
this.tools = tools;
}

run()方法中加入:

1
2
if (tools != null)
tools.setLocation(0, 0);

升级2

有时候误操作的时候,我必须得截图一下才能进行其他操作。
我希望在误操作的时候可以退出截图。比如按下esc按键。
按下alt+e让截图窗口隐藏

修改好了,我现在该代码都没注意改

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.JIntellitype;

/**
* 利用JIntellitype实现全局热键设置
*
* @author Jeby Sun
*
*/
public class GlobleHotKeyDemo extends JFrame
{

private static final long serialVersionUID = 1L;

// 定义热键标识,用于在设置多个热键时,在事件处理中区分用户按下的热键
public static final int FUNC_KEY_MARK = 1;
public static final int EXIT_KEY_MARK = 0;

JButton msgBtn;
JButton exitBtn;

public GlobleHotKeyDemo()
{
this.setTitle("全局热键设置");
this.setBounds(100, 100, 600, 400);
this.setLayout(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

msgBtn = new JButton("弹出框(Alt+S)");
// 设置按钮边距
msgBtn.setMargin(new Insets(0, 0, 0, 0));
msgBtn.setFocusable(false);
msgBtn.setBounds(20, 20, 120, 30);
msgBtn.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
showMessage();
}
});
this.add(msgBtn);

exitBtn = new JButton("退出(Alt+Q)");
exitBtn.setMargin(new Insets(0, 0, 0, 0));
exitBtn.setFocusable(false);
exitBtn.setBounds(160, 20, 120, 30);
exitBtn.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
this.add(exitBtn);

// 第一步:注册热键,第一个参数表示该热键的标识,第二个参数表示组合键,如果没有则为0,第三个参数为定义的主要热键
JIntellitype.getInstance().registerHotKey(FUNC_KEY_MARK,
JIntellitype.MOD_ALT, (int) 'S');
JIntellitype.getInstance().registerHotKey(EXIT_KEY_MARK,
JIntellitype.MOD_ALT, (int) 'Q');

// 第二步:添加热键监听器
JIntellitype.getInstance().addHotKeyListener(new HotkeyListener()
{

@Override
public void onHotKey(int markCode)
{
switch (markCode)
{
case FUNC_KEY_MARK :
showMessage();
break;
case EXIT_KEY_MARK :
System.exit(0);
break;
}
}
});

this.setVisible(true);
}

public void showMessage()
{
JOptionPane.showMessageDialog(null, "就算把窗口最小化,按快捷键Alt+S也可以弹出提示框哦!",
"弹出框标题", JOptionPane.INFORMATION_MESSAGE);
}

public static void main(String[] args)
{
new GlobleHotKeyDemo();
}
}

其实,jintellitype的使用非常简单,就3个步骤:
第一步:添加jar包和dll文件;
第二步:注册热键;
第三步:添加热键监听器,实现接口的方法;
参考:https://www.cnblogs.com/jebysun/p/3969363.html

参考:https://blog.csdn.net/iteye_11213/article/details/81886200

JIntellitype提供了简单的调用方法去注册系统热键。操作简单,示例明确,下载后阅读一下readme.txt文档,就可以使用了。

使用时首先要定义一个实现了HotkeyListener接口的类,实现其onHotKey(int)方法,这个方法接收一个数字,作为标志

然后就可以使用JIntellitype.getInstance().registerHotKey(int,int,int)方法注册需要的热键了,其中第一个参数将是触发时传递个onHotKey方法的参数,所以两者要保持统一,第二个参数为ctrl、alt、shift等的组合结果,第三个一般为组合键的字母。
示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.iflysse.swing;
import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.JIntellitype;
/**
* @author ZYWANG
*/
public class HotkeyTest
{
public static void main(String[] args) throws InterruptedException
{
//注册一个ctrl+alt+a的热键
JIntellitype.getInstance().registerHotKey(100, JIntellitype.MOD_CONTROL+JIntellitype.MOD_ALT, (int)'T');
//添加热键监听器
JIntellitype.getInstance().addHotKeyListener(new HotkeyListener()
{
@Override
public void onHotKey(int arg0)
{
System.out.println(arg0);//打印参数
//JIntellitype.getInstance().unregisterHotKey(arg0);//用于移除热键注册的方法
System.exit(0);
}
});
Thread.sleep(10000000);
}
}

JIntellitype下载地址:http://melloware.com/download/ (打开页面,找到JIntellitype)
下载地址:https://code.google.com/archive/p/jintellitype/downloads,注意需要科学上网。
附件中提供了一个jintellitype-1.3.4-dist版本备用

AWT简介

Java1.0的出现带来了抽象窗口工具箱(AWT)。设计目标是希望构建一个通用的GUI,使得利用它编写的程序能够运行在所有的平台上,以实现Sun公司提出的口号“一次编写,随处运行”。 Java AWT中包含了许多类来支持GUI设计。AWT由Java的 Java.awt包提供,该包中有许多用来设计GU的组件类,如按钮、菜单、列表、文本框等组件类;同时还包含窗口、面板等容器类。AWT的具体层次结构如图16.1所示。

Java提供了一系列AWT软件包,其中主要的包及包的描述如图16.2所示。

  • java.awt包:是AWT的核心包,包含用于创建用户界面和绘制图形图像的所有类

  • java.awt包:

    • AWT的核心包,包含用于创建用户界面和绘制图形图像的所有类
  • java.awt.color包:

    • 提供定义颜色及其空间
  • java.awt.datatransfer包:

    • 提供在应用程序之间和在应用程序内部传输数据的接口和类
  • java.awt.event包:

    • 提供处理由AWT组件所激发的各类事件的接口和类
  • java.awt.font包:

    • 提供各种字体,包括类及接口
  • java.awt.image包:

    • 用于图像处理,提供创建和修改图像的各种类
  • java.awt.print包:

    • 2D图像的API包,为通用的打印API提供类和接口
      java.awt包提供了基本的Java程序的GUI设计工具。主要包括组件、容器和布局管理器三个概念,其具体描述如下所示。

GUI设计工具组件

  • 组件Component):图形用户界面的最基本组成部分是组件,组件是一个可以以图形化的方式显示在屏幕上并能与用户进行交互的对象,例如个按钮,一个标签等
  • 容器( Container):是Component(组件)的子类,容器本身是一个组件具有组件的所有性质,但是其主要功能是容纳其他组件和容器
  • 布局管理器(LayoutManager): 每个容器都有一个布局管理器,使用布局管理器可以对容器中的某个组件进行定位或判断其大小尺寸

Swing简介

Swing是Java基础类库( Java Foundation Classes)中有关图形界面的类库。 Swing扩展自AWT。例如JFrame扩展自 Frame, JButton扩展自Component等。基本上AWT中的每种控件都能在Swing中找到替代品,比如AWT中的Button对应于 Swing中的 JButton,AWT中的 TextField对应于 Swing中的 JTextField等。

Swing包是JFC(Java Foundation Classes)的一部分,它由许多包组成,这些包的名称及描述如表16.1所示。

容器类

窗口( JFrame)、面板( JPanel)和对话框(J)是Swing中提供用来创建表示图形用户界面的类。该类的对象将被当作容器使用,所有的 Swing组件都必须被添加到容器中,才能被显示出来。

JFrame类

Jframe是一个窗口容器组件,可以被显示在用户桌面上,同时也是一个框架,在其中,可以添加需要的其他的Swing组件。 **Jframe是少数几个不是通过绘制的方式显示的Swing组件**。 Jframe类的构造方法如下所示

  • public JFrame(String title)
    • 构造一个初始状态是不可见的、有指定标题的JFrame对象。参数 title指明了 JFrame对象的标题

Jframe类中还提供了一些与窗口有关的方法。其主要方法与方法描述如表16.2所示。

JDialog类

JDialog是一个用来创建对话框的类,是 Dialog类的子类。创建的 JDialog对象可以用来向用户返回信息,接收用户的输入,实现与用户的交互

JDialog与Jframe的区别

JDialog对象需要依赖于其他的对话框(比如 Jframe)而存在,当它所依赖的对话框关闭或最小化的时候,该对话框也随之关闭或最小化。

JDialog类创建对话框对象的构造方法如图16.7所示。

  • Dialog(JFrame frame,String s)
    • 创建一个对话框对象,初始状态为不可见。参数s用来设置对话框的名字
  • Dialog(frame frame, String s, boolean b)
    • 创建一个对话框对象。参数s用来设置对话框的名字,参数b用来决定该对话框的模式

JDialog类中的主要方法及方法描述如表16.3所示。

JPanel类

在得到了 JFrame的内容面板后我们就可以直接将其他的 Swing组件放在其中,或者直接在上面描绘图画或文字,但是习惯上一般不会这么做。通常会将这些图画或文字信息描绘在名为JPanel的容器上,然后再将 JPanel实例放在内容面板上。这样可以使得面板上的布局更合理。JPanel通常只作为纯粹的容器来使用,它不能像框架、窗口或者对话框那样独立存在。 JPanel的构造方法如下所示。

  • JPanel()
    • 构造一个使用默认的布局管理器创建的面板
  • JPanel(LayoutManager layout)
    • 构造一个使用指定布局管理器的面板

Swing常用基本组件

创建图形用户界面GUI,就是为了让计算机程序更好的和用户交互。 Java Swing提供了二十多种不同的用户界面组件。所有的Swng组件都是从javax.swing.Jcomponent类中派生而来的,从而继承了组件所特有的属性和方法

常用组件的共性操作

Swing类库中的组件都继承自 javax.swing.JComponent,因此都具有 JComponent的操作,包括设置背景色,设置前景色设置字体以及设置是否禁用等。表16.4中是 JComponent中常用的方法及方法描述。

按钮( JButton)

按钮是用户界面中常用的组件。用户使用 Swing按钮可以显示图像,将整个按钮设置为窗口默认图标,来处理鼠标在按钮上的事件。java.swing包中提供了标准的按压式按钮( JButton)。同时提供了选择式按钮:多选择( JCheckBox)、单选择( JRadioButton)等。我们在这里先来讲解 JButton的知识JButton的构造方法如图16.1所示。

  • public JButton ()方法
    • 用于创建不带有设置文本或图标的按钮
  • public JButton(Icon icon)方法
    • 用于创建一个带图标的按钮
  • public JButton(String text)方法
    • 用于创建一个带文本的按钮
  • public JButton(Action a)方法
    • 用于创建一个按钮,其属性从所提供的 Action中获取

文本框( JTextField)与密码输入框( JPasswordField)

文本框( JTextField)也是一种常见的组件,用于处理一行文本(中间没有回车符)。 JTextField是JTextComponent的子类。密码输入框是 JTextField的个子类。 JTextField和 PasswordField的构造函数形式和常用方法完全一样。这里只列出 JTextField的构造函数,如下所示。

  • JTextField()
    • 构造一个空文本域
  • JTextField(String text)
    • 构造一个显示指定字符串的文本域
  • JTextField(int columns)
    • 构造一个显示指定列数的空文本域
  • JTextField(String text,int columns)
    • 构造一个具有显示指定字符串,指定列数的文本域

      文本域( JTextArea)

      文本域( JTextArea)也是一种常用组件,用于处理多行文本。 JTextArea同 JTextField一样,都是JTextcomponent的子类,因此它们的很多操作都类似,我们不再赘述。 JTextArea的构造函数如下所示:
  • JTextArea
  • 构造一个空文本区
  • JTextArea(String text)
    • 构造一个显示指定字符串的文本区
  • JTextArea(int columns)
    • 构造一个显示指定列数的空文本区
  • JTextArea(String text, int columns)
    • 构造一个具有显示指定字符串,指定列数的文本区

标签( JLabel)

标签( JLabel)用来显示一段文本,常用在 JTextField或者 JTextArea前面,提示用户要填写什么样的信息。JLabel用于显示文字,也可以同时显示文字和图标,一般不用于接收鼠标键盘的动作。 JLabel的构造方法如下所示。

  • public JLabel (String text)
  • 使用左对齐字符串来构造一个标签
  • public JLabel (Icon icon)
    • 使用左对齐图标来构造一个标签
  • public JLabel (String text, int align)
    • 构造一个显示指定列数的空文本区
  • public JLabel(String text, Icon icon, int align)
    • 构造一个具有显示指定字符串,指定列数的文本区

先搬运到这里,后面再看看。看了这么多还是没能达到我想要的结果:设置一个截图的软件,然后自动调用百度识图获取JSON数据,并去除识别的文字,复制到剪贴板中。

源码:https://www.cnblogs.com/feitianshaoxai/p/6560110.html

上面代码实现了截图的操作,我要在上面的代码中加入自动保存然后调用百度识图的操作。具体可以模仿上面的保存函数

加入的百度文字识图按钮:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 百度识图按钮
JButton baiduOCRButton = new JButton("百度文字识别");
baiduOCRButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
try
{
// 保存截图
parent.baiduOCR();
} catch (IOException e1)
{
e1.printStackTrace();
}
}
});
toolBar.add(baiduOCRButton);

实现算法:

1
2
3
4
5
6
7
8
// 调用百度识图
public void baiduOCR() throws IOException
{
// 写入文件
ImageIO.write(saveImage, "png", new File("1.png"));
Thread baiduOCR=new Thread(new BaiduOCR("1.png",this));
baiduOCR.start();
}

说明:直接把截图保存在工程路径下的“1.png”文件中。然后启动一个baiduOCR线程来处理这个图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package release.ocr.baidu;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONObject;
import com.baidu.aip.ocr.AipOcr;
import clipboard.util.SysClipboardUtil;
import net.sf.json.JSONArray;

public class BaiduOCR implements Runnable
{
// 设置APPID/AK/SK
public static final String APP_ID = "你的百度APP_ID";
public static final String API_KEY = "你的百度API_KEY";
public static final String SECRET_KEY = "你的百度SECRET_KEY";
//窗体引用,用于使得窗体不可见
ScreenShotWindow screenShotWindow;
//文件路径,我们识别的就是这个图片
String path;
//通过构造函数传入参数
public BaiduOCR(String path,ScreenShotWindow screenShotWindow)
{
this.path=path;
this.screenShotWindow=screenShotWindow;
}
@Override
public void run()
{
//让窗体不可见,以便用户可以进行其他操作
ScreenShotOCR.notVisiabl();
//调用百度文字识别接口
baiduOCR(path);
//回调函数,执行完毕后关闭程序
ScreenShotWindow.Exit();

}
/**
* 调用百度文字识别
*/
public static void baiduOCR(String path)
{
// 初始化一个AipOcr
AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
// 可选:设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
// 调用接口取得识别的结果:JSON数据
JSONObject res = client.basicGeneral(path,
new HashMap<String, String>());
String text = res.toString(2);
//从JSON数据中取出翻译的结果
//转为HashMap
HashMap<String, Object> resMap = (HashMap<String, Object>) res.toMap();
// 迭代器
Iterator<Map.Entry<String, Object>> it = resMap.entrySet().iterator();
// 缓冲,用来存储识别结果
StringBuilder sbBuilder = new StringBuilder();
Map.Entry<String, Object> entry;
//遍历Map集合
while (it.hasNext())
{
entry = it.next();
//找到翻译结果组
if (entry.getKey().equals("words_result"))
{
// 获取词组
JSONArray jsonArray = JSONArray.fromObject(entry.getValue());
System.out.println(jsonArray.toString());
for (Object object : jsonArray)
{
sbBuilder.append(object.toString());
}
}
}
//获取识别结果
String words = sbBuilder.toString();
//使用正则表达式删除无用信息,只留下翻译的结果
words = words.replaceAll("(?:(?:\\\"\\})?\\{\\\"words\\\":\\\"|\\\"\\})", "");
SysClipboardUtil.setSysClipboardText(words);
}
}

完整的代码

ScreenShotOCR类

ScreenShotOCR类实现截图的功能,窗体的显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
package release.ocr.baidu;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JToolBar;
import javax.swing.JWindow;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;

public class ScreenShotOCR
{
static ScreenShotWindow ssw;
public static void main(String[] args)
{

EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
ssw = new ScreenShotWindow();
ssw.setVisible(true);
} catch (AWTException e)
{
e.printStackTrace();
}
}
});
}
// 回调函数,使得当前窗口不可见。
public static void notVisiabl()
{
ssw.setVisible(false);
}

}
/*
* 截图矩形窗口
*/
class ScreenShotWindow extends JWindow
{
private int orgx, orgy, endx, endy;
private BufferedImage image = null;
private BufferedImage tempImage = null;
private BufferedImage saveImage = null;

private ToolsWindow tools = null;

public ScreenShotWindow() throws AWTException
{
// 获取屏幕尺寸
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
// 设置窗口显示大小
this.setBounds(0, 0, d.width, d.height);

// 截取整个屏幕
Robot robot = new Robot();
image = robot
.createScreenCapture(new Rectangle(0, 0, d.width, d.height));

// 设置鼠标监听事件
this.addMouseListener(new MouseAdapter()
{
// 鼠标按下
@Override
public void mousePressed(MouseEvent e)
{
// 鼠标松开时记录结束点坐标,并隐藏操作窗口
orgx = e.getX();
orgy = e.getY();

if (tools != null)
{
tools.setVisible(false);
}
}
@Override
public void mouseReleased(MouseEvent e)
{
// 鼠标松开时,显示操作窗口
if (tools == null)
{
tools = new ToolsWindow(ScreenShotWindow.this, e.getX(),
e.getY());
} else
{
tools.setLocation(e.getX(), e.getY());
}
tools.setVisible(true);
tools.toFront();
}
});

this.addMouseMotionListener(new MouseMotionAdapter()
{

@Override
public void mouseDragged(MouseEvent e)
{
// 鼠标拖动时,记录坐标并重绘窗口
endx = e.getX();
endy = e.getY();

// 临时图像,用于缓冲屏幕区域放置屏幕闪烁
Image tempImage2 = createImage(ScreenShotWindow.this.getWidth(),
ScreenShotWindow.this.getHeight());
Graphics g = tempImage2.getGraphics();
g.drawImage(tempImage, 0, 0, null);
int x = Math.min(orgx, endx);
int y = Math.min(orgy, endy);
int width = Math.abs(endx - orgx) + 1;
int height = Math.abs(endy - orgy) + 1;
// 加上1防止width或height0
g.setColor(Color.BLUE);
g.drawRect(x - 1, y - 1, width + 1, height + 1);
// 减1加1都了防止图片矩形框覆盖掉
saveImage = image.getSubimage(x, y, width, height);
g.drawImage(saveImage, x, y, null);

ScreenShotWindow.this.getGraphics().drawImage(tempImage2, 0, 0,
ScreenShotWindow.this);
}
});
}

@Override
public void paint(Graphics g)
{
RescaleOp ro = new RescaleOp(0.8f, 0, null);
tempImage = ro.filter(image, null);
g.drawImage(tempImage, 0, 0, this);
}
// 保存图像到文件
public void saveImage() throws IOException
{
JFileChooser jfc = new JFileChooser();
jfc.setDialogTitle("保存");

// 文件过滤器,用户过滤可选择文件
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG",
"png");
jfc.setFileFilter(filter);

// 初始化一个默认文件(此文件会生成到桌面上)
SimpleDateFormat sdf = new SimpleDateFormat("yyyymmddHHmmss");
String fileName = sdf.format(new Date());
File filePath = FileSystemView.getFileSystemView().getHomeDirectory();
File defaultFile = new File(
filePath + File.separator + fileName + ".png");
jfc.setSelectedFile(defaultFile);

int flag = jfc.showSaveDialog(this);
if (flag == JFileChooser.APPROVE_OPTION)
{
File file = jfc.getSelectedFile();
String path = file.getPath();
// 检查文件后缀,放置用户忘记输入后缀或者输入不正确的后缀
if (!(path.endsWith(".png") || path.endsWith(".PNG")))
{
path += ".png";
}
// 写入文件
ImageIO.write(saveImage, "png", new File(path));
System.exit(0);
}
}
// 调用百度识图
public void baiduOCR() throws IOException
{
// 写入文件
ImageIO.write(saveImage, "png", new File("1.png"));
Thread baiduOCR = new Thread(new BaiduOCR("1.png", this));
baiduOCR.start();
}
public static void Exit()
{
System.exit(0);
}
}

/*
* 操作窗口
*/
class ToolsWindow extends JWindow
{
private ScreenShotWindow parent;

public ToolsWindow(ScreenShotWindow parent, int x, int y)
{
this.parent = parent;
this.init();
this.setLocation(x, y);
this.pack();
this.setVisible(true);
}

private void init()
{

this.setLayout(new BorderLayout());
JToolBar toolBar = new JToolBar("Java 截图");

// 保存按钮
JButton saveButton = new JButton("保存");
saveButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
try
{
// 保存截图
parent.saveImage();
} catch (IOException e1)
{
e1.printStackTrace();
}
}
});
toolBar.add(saveButton);

// 百度识图按钮
JButton baiduOCRButton = new JButton("百度文字识别");
baiduOCRButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
try
{
// 保存截图
parent.baiduOCR();
} catch (IOException e1)
{
e1.printStackTrace();
}
}
});
toolBar.add(baiduOCRButton);

// 关闭按钮
JButton closeButton = new JButton("退出");
closeButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
toolBar.add(closeButton);

this.add(toolBar, BorderLayout.NORTH);
}

}

BaiduOCR类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package release.ocr.baidu;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONObject;
import com.baidu.aip.ocr.AipOcr;
import clipboard.util.SysClipboardUtil;
import net.sf.json.JSONArray;

public class BaiduOCR implements Runnable
{
// 设置APPID/AK/SK
public static final String APP_ID = "你的BaiduAPP_ID";
public static final String API_KEY = "你的";
public static final String SECRET_KEY = "你的";
//窗体引用
ScreenShotWindow screenShotWindow;
//文件路径
String path;
public BaiduOCR(String path,ScreenShotWindow screenShotWindow)
{
this.path=path;
this.screenShotWindow=screenShotWindow;
}
@Override
public void run()
{
//让窗体不可见
ScreenShotOCR.notVisiabl();
//调用百度文字识别接口
baiduOCR(path);
//回调函数,执行完毕后关闭程序
ScreenShotWindow.Exit();

}
/**
* 调用百度文字识别
*/
public static void baiduOCR(String path)
{
// 初始化一个AipOcr
AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
// 可选:设置网络连接参数
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
// 调用接口
JSONObject res = client.basicGeneral(path,
new HashMap<String, String>());
String text = res.toString(2);
HashMap<String, Object> resMap = (HashMap<String, Object>) res.toMap();
// 第二种:
Iterator<Map.Entry<String, Object>> it = resMap.entrySet().iterator();
// 缓冲,用来存储识别结果
StringBuilder sbBuilder = new StringBuilder();
Map.Entry<String, Object> entry;
while (it.hasNext())
{
entry = it.next();
if (entry.getKey().equals("words_result"))
{
// 获取词组
JSONArray jsonArray = JSONArray.fromObject(entry.getValue());
System.out.println(jsonArray.toString());
for (Object object : jsonArray)
{
sbBuilder.append(object.toString());
}
}
}
String words = sbBuilder.toString();
words = words.replaceAll("(?:(?:\\\"\\})?\\{\\\"words\\\":\\\"|\\\"\\})", "");
SysClipboardUtil.setSysClipboardText(words);
}
}

公式显示位置

行内公式

在公式两边各自加上一个美元符号即使行内公式

1
这是文本$a^2+b^2=c^2$这是文本

显示效果:
这是文本$a^2+b^2=c^2$这是文本

行间公式

在公式两边各自加上两个美元符号即使行将公式:

1
这是文本$$a^2+b^2=c^2$$这是文本

显示效果:
这是文本$$a^2+b^2=c^2$$这是文本

数学符号

上下标

在LaTex中用^_表明上下标。注意如果上下标只对其后面的一个字符起作用,如果上下标的内容超过一个字符,则需要用花括号{}包裹,否则上下标只对后面的一个符号起作用

1
$$p^3_{ij}\qquad\sum_{K=1}^3ka^x+y\qquad\neq a^{x+y}$$

显示效果:
$$p^3_{ij}\qquad\sum_{K=1}^3ka^x+y\qquad\neq a^{x+y}$$

导数符号

导数符号'是一个特殊的上标,可以适当连用表示多阶导数,也可以在其后连用上标:

1
$f(x)=x^2 \quad f'(x)=2x \quad f''^{2}=4$

显示效果:
$f(x)=x^2 \quad f’(x)=2x \quad f’’^{2}=4$

偏导 条件偏导

偏导符号$\partial$

1
$\left.\frac{\partial f(x,y)}{\partial x}\right|_{x=0}$

$\left.\frac{\partial f(x,y)}{\partial x}\right|_{x=0}$

分式

如果是简单的根式,可以写成斜分式的形式,如3/8:,在latex中分式一般使用\frac{分子}{分母}来书写。不过这种分式的大小在行间公式是正常显示大小,而在行内被极度压缩了。amsmath提供了方便的命令\dfrac{分子}{分母}\tfrac{分子}{分母},令用户能够在行内使用正常大小的行内公式。
显示效果:

1
斜分式: $3/8 \qquad $,压缩分式:$\frac{3}{8}\qquad$ ,显示正常大小:$\dfrac{3}{8}$

斜分式: $3/8 \qquad $,压缩分式:$\frac{3}{8}\qquad$ ,显示正常大小:$\dfrac{3}{8}$

根式

一般的根式使用\sqrt{…}表示,表示n此方根式写成\sqrt[n]{…}:

1
2
3
4
$\sqrt{x} \Leftrightarrow x^{1/2}
\quad \sqrt[3]{2}
\quad \sqrt{x^{2}+\sqrt{y}}$
$

显示效果:
$\sqrt{x} \Leftrightarrow x^{1/2}
\quad \sqrt[3]{2}
\quad \sqrt{x^{2}+\sqrt{y}}
$

特殊的分式形式,如二项式结构,由amsmath宏包的\binom命令生成:

1
2
3
4
Pascal's rule is
$$
\binom{n}{k}=\binom{n-1}{k}+\binom{n-1}{k-1}
$$

Pascal’s rule is
$$
\binom{n}{k}=\binom{n-1}{k}+\binom{n-1}{k-1}
$$

无穷大符号

1
$\infty$

$\infty$

这个是个缩写,原单词(infinity)读音:

省略号

名称 符号 效果
水平省略号 \dots $\dots$
水平省略号 \cdots $\cdots$
竖直省略号 \vdots $\vdots$
斜排省略号 \ddots $\ddots$
1
2
$a_1,a_2,\dots,a_n$
$a_1,a_2,\cdots,a_n$

显示效果如下:
$a_1,a_2,\dots,a_n$
$a_1,a_2,\cdots,a_n$

\cdots\dots是完全等效的,它们既能用在公式中,也用在文本里作为省略号
除此之外,在矩阵中可能会用到竖排的$\vdots$(\vdots)和斜排的$\ddots$(\ddots)

关系符

LaTex常见的关系符号除了可以直接输入的=,>,<,其他符号用命令输入,常用的有不等于: $\ne$ (\ne),大于等于号: $\ge$ (\ge)和小于等于号:$\le$ (\le),约等于号: $\approx$ (\approx),等价 $\equiv$ (\equiv),正比: $\propto$ (\propto),相似: $\sim$ (\sim)等等。
LaTex还提供了自定义二元关系符的命令\stackrel,用于将一个符号叠加在原有的二元关系符之上:

1
2
3
$$
f_n(x) \stackrel{*}{\approx} 1
$$

$$
f_n(x) \stackrel{*}{\approx} 1
$$

巨算子

积分号,求和号等符号称为**巨算子**。

名称 符号 效果
积分号 \int $\int$
求和号 \sum $\sum$
1
2
3
4
5
6
$$
\sum_{i=1}^n \quad
\int_0^{\frac{\pi}{2}} \quad
\oint_0^{\frac{\pi}{2}} \quad
\prod_\epsilon
$$

$$
\sum_{i=1}^n \quad
\int_0^{\frac{\pi}{2}} \quad
\oint_0^{\frac{\pi}{2}} \quad
\prod_\epsilon
$$

巨算符的上下标用作其上下限。行间公式中,积分号默认将上下限放在右上角和右下角,求和号默认在上下方;行内公式一律默认在右上角和右下角。可以在巨算符后使用\limits手动令上下限显示在上下方,\nolimits则相反,即不显示在上下方,也就是显示在右上角,右下角。

1
2
3
4
5
$$
\sum\nolimits_{i=1}^n \quad
\int\limits_0^{\frac{\pi}{2}} \quad
\prod\nolimits_\epsilon
$$

$$
\sum\nolimits_{i=1}^n \quad
\int\limits_0^{\frac{\pi}{2}} \quad
\prod\nolimits_\epsilon
$$

极限符号

行间公式极限

行间公式下标默认放在符号的下方,所以直接再极限符号\lim下方写上符号极限范围即可:

1
$${\lim_{x \to +\infty}}$$

$${\lim_{x \to +\infty}}$$

1
$${\lim_{x \to -\infty}}$$

$${\lim_{x \to -\infty}}$$

1
$${\lim_{x \to 0}}$$

$${\lim_{x \to 0}}$$

1
$${\lim_{x \to 0^+}}$$

$${\lim_{x \to 0^+}}$$

1
$${ \lim_{x \to 0} \frac{3x^2 +7x^3}{x^2 +5x^4} = 3}$$

$${ \lim_{x \to 0} \frac{3x^2 +7x^3}{x^2 +5x^4} = 3}$$

行间极限

行间的下标默认放在右下角,可以使用\limits_{下标}把下标放到符号下方即可。实例如下所示:

1
${\lim \limits_{x \to -\infty}}$

行间极限符号:${\lim \limits_{x \to -\infty}}$

集合相关符号

元素与集合的关系

名称 符号 效果
属于 \in $\in$
不属于 \notin $\notin$

集合与集合相关的关系

名称 符号 效果
空集 \emptyset $\emptyset$
子集 \subset $\subset$
真子集 \subseteq $\subseteq$
交集 \bigcap和\cap $\bigcap$和$\cap$
并集 \bigcup和\cup $\bigcup$和$\cup$

数学重音和上下括号

数学符号可以像文字一样加重音,比如对时间求导的符号$\dot{r}$(\dot{r})、$ddot{r}$(ddot{r})、表示向量的箭头$vec{r}$(vec{r})、表示欧式空间单位向量的$\hat{\mathbf{e}}$(\hat{\mathbf{e}})等,详见表4.9。使用时要注意重音符号的作用区域,一般应当对某个符号而不是不符号加下表使用重音:

1
2
3
4
$\bar{x_0} \quad \bar{x}_0$\\[5pt]
$\vec{x_0} \quad \vec{x}_0$\\[5pt]
$\hat{\mathbf{e}_x} \quad
\hat{\mathbf{e}}_x$

$\bar{x_0} \quad \bar{x}_0$
$\vec{x_0} \quad \vec{x}_0$
$\hat{\mathbf{e}_x} \quad
\hat{\mathbf{e}}_x$

LATEX也能为多个字符加重音,包括直接画线的\overline\underline命令(可叠加使用)、宽重音符号\widehat、表示向量的箭头\overrightarrow等。后两者详见表4.9和4.11等。

1
2
3
4
5
$0.\overline{3} =
\underline{\underline{1/3}}$
$\hat{XY} \qquad \widehat{XY}$
$\vec{AB} \qquad
\overrightarrow{AB}$

$0.\overline{3} =
\underline{\underline{1/3}}$
$\hat{XY} \qquad \widehat{XY}$
$\vec{AB} \qquad
\overrightarrow{AB}$

\overbrace和\underbrace命令用来生成上/下括号,各自可带一个上/下标公式。

1
2
3
$\underbrace{\overbrace{a+b+c}^6
\cdot \overbrace{d+e+f}^7}
_\text{meaning of life} = 42$

$\underbrace{\overbrace{a+b+c}^6
\cdot \overbrace{d+e+f}^7}
_\text{meaning of life} = 42$

多行公式

长公式折行

通常来讲应当避免写出超过一行而需要折行的长公式。如果一定要折行的话,优先在等号之前折行,其次在加号、减号之前,再次在乘号、除号之前。其它位置应当避免折行
amsmath宏包的multline环境提供了书写折行长公式的方便环境。它允许用\\\\(markdown中显示:\\)折行,将公式编号放在最后一行。多行公式的首行左对齐末行右对齐其余行居中
因为markdown中\是转义符,所以\\才表示一个\,所以这里要写四个\(\\\\)

1
2
3
4
5
6
$$
\begin{multline}a + b + c + d + e + f+ g + h + i \\\\
= j + k + l + m + n\\\\
= o + p + q + r + s\\\\
= t + u + v + x + z\end{multline}
$$

$$
\begin{multline}a + b + c + d + e + f+ g + h + i \\
= j + k + l + m + n\\
= o + p + q + r + s\\
= t + u + v + x + z\end{multline}
$$

与表格不同的是,公式的最后一行不写\\,如果写了,反倒会产生一个多余的空行。类似equation\*multline\*环境排版不带编号的折行长公式。

需要注意的是,只是在Hexo的默认Markdown渲染器中才需要使用四个反斜杠
为了通用,本文下面的演示代码都使用两个反斜杠

多行公式

更多的情况是,我们需要罗列一系列公式,并令其按照等号对齐。读者可能阅读过其它手册或者资料,知道LATEX提供了eqnarray环境。它按照等号左边——等号——等号右边呈三列对齐,但等号周围的空隙过大,加上公式编号等一些bug,目前已不推荐使用

目前最常用的是align环境,它将公式用&隔为两部分并对齐。分隔符通常放在等号左边:

1
2
3
4
5
6
$$
\begin{align}
a & = b + c \\
& = d + e
\end{align}
$$

$$
\begin{align}
a & = b + c \\
& = d + e
\end{align}
$$

align环境会给每行公式都编号。我们仍然可以用\notag去掉某行的编号。在以下的例子,为了对齐加号,我们将分隔符放在等号右边,这时需要给等号后添加一对括号{}以产生正常的间距:

1
2
3
4
5
6
7
8
$$
\begin{align}
a ={} & b + c \\
={} & d + e + f + g + h + i+ j + k + l \notag \\
& + m + n + o \\
={} & p + q + r + s
\end{align}
$$

$$
\begin{align}
a ={} & b + c \\
={} & d + e + f + g + h + i+ j + k + l \notag \\
& + m + n + o \\
={} & p + q + r + s
\end{align}
$$

align还能够对齐多组公式,除等号前的&之外,公式之间也用&分隔:

1
2
3
4
5
6
$$
\begin{align}
a &=1 & b &=2 & c &=3 \\
d &=-1 & e &=-2 & f &=-5
\end{align}
$$

$$
\begin{align}
a &=1 & b &=2 & c &=3 \\
d &=-1 & e &=-2 & f &=-5
\end{align}
$$

如果我们不需要按等号对齐,只需罗列数个公式,gather将是一个很好用的环境:

1
2
3
4
5
6
7
8
$$
\begin{gather}
a = b + c \\
d = e + f + g \\
h + i = j + k \notag \\
l + m = n
\end{gather}
$$

$$
\begin{gather}
a = b + c \\
d = e + f + g \\
h + i = j + k \notag \\
l + m = n
\end{gather}
$$

align和gather有对应的不带编号的版本align\*gather\*

公用编号的多行公式

另一个常见的需求是将多个公式组在一起公用一个编号,编号位于公式的居中位置。为此,amsmath宏包提供了诸如aligned、gathered等环境,与equation环境套用。以-ed结尾的环境用法与前一节不以-ed结尾的环境用法一一对应。我们仅以aligned举例:

1
2
3
4
5
6
7
8
9
10
$$
\begin{equation}
\begin{aligned}
a &= b + c \\
d &= e + f + g \\
h + i &= j + k \\
l + m &= n
\end{aligned}
\end{equation}
$$

$$
\begin{equation}
\begin{aligned}
a &= b + c \\
d &= e + f + g \\
h + i &= j + k \\
l + m &= n
\end{aligned}
\end{equation}
$$

split环境和aligned环境用法类似,也用于和equation环境套用,区别是split只能将每行的一个公式分两栏,aligned允许每行多个公式多栏。

公式中的间距

前文提到过,绝大部分时候,数学公式中各元素的间距是根据符号类型自动生成的,需要我们手动调整的情况极少。我们已经认识了两个生成间距的命令\quad\qquad。在公式中我们还可能用到的间距包括\,\:\;以及负间距\!,其中\quad\qquad\,在文本和数学环境中可用,后三个命令只用于数学环境。文本中的\␣也能使用在数学公式中。
此处应该有图片,但是我的图片好像用不了了

一个常见的用途是修正积分的被积函数$f(x)$和微元$dx$之间的距离。注意微元里的$d$用的是直立体:

1
2
3
4
5
$$
\int_a^b f(x)\mathrm{d}x
\qquad
\int_a^b f(x)\,\mathrm{d}x
$$

$$
\int_a^b f(x)\mathrm{d}x
\qquad
\int_a^b f(x),\mathrm{d}x
$$

另一个用途是生成多重积分号。如果我们直接连写两个\int,之间的间距将会过宽,此时可以使用负间距\\!修正之。不过amsmath提供了更方便的多重积分号,如**二重积分\iint三重积分\iiint**等。

数组和矩阵

为了排版二维数组,LATEX提供了array环境,用法与tabular环境极为类似,也需要定义列格式,并用\\换行。数组可作为一个公式块,在外套用\left\right等定界符:

1
2
3
4
5
6
7
8
9
10
$$
\mathbf{X} = \left(
\begin{array}{cccc}
x_{11} & x_{12} & \ldots & x_{1n}\\
x_{21} & x_{22} & \ldots & x_{2n}\\
\vdots & \vdots & \ddots & \vdots\\
x_{n1} & x_{n2} & \ldots & x_{nn}\\
\end{array}
\right)
$$

还是因为是在markdown文档中\需要转义,所以两个斜杠:\\,在markdown文档中需要使用四个斜杠:\\\\来表示
$$
\mathbf{X} = \left(
\begin{array}{cccc}
x_{11} & x_{12} & \ldots & x_{1n}\\
x_{21} & x_{22} & \ldots & x_{2n}\\
\vdots & \vdots & \ddots & \vdots\\
x_{n1} & x_{n2} & \ldots & x_{nn}\\
\end{array}
\right)
$$

值得注意的是,上一节末尾介绍的aligned等环境也可以用定界符包裹。我们还可以利用空的定界符排版出这样的效果:

1
2
3
4
5
6
7
8
$$
|x| = \left\{
\begin{array}{rl}
-x & \text{if } x < 0,\\
0 & \text{if } x = 0,\\
x & \text{if } x > 0.
\end{array} \right.
$$

$$
|x| = \left \{
\begin{array}{rl}
-x & \text{if } x < 0,\\
0 & \text{if } x = 0,\\
x & \text{if } x > 0.
\end{array} \right.
$$

我不知道这里为什么显示不正常,可以能不支持把,下面的例子同样也可额完成,衣柜对于分段函数可以写下面的这种形式。

分段函数

不过上述例子可以用amsmath提供的cases环境更轻松地完成:

1
2
3
4
5
6
$$ |x| =
\begin{cases}
-x & \text{if } x < 0,\\
0 & \text{if } x = 0,\\
x & \text{if } x > 0.
\end{cases} $$

$$ |x| =
\begin{cases}
-x & \text{if } x < 0,\\
0 & \text{if } x = 0,\\
x & \text{if } x > 0.
\end{cases} $$

我们当然也可以用array环境排版各种矩阵。amsmath宏包还直接提供了多种排版矩阵的环境,包括不带定界符的matrix,以及带各种定界符的矩阵pmatrix(()、bmatrix([)、Bmatrix({)、vmatrix(|)、Vmatrix(||)。使用这些环境时,无需给定列格式5:

1
2
3
4
5
6
7
8
9
10
11
$$
\begin{matrix}
1 & 2 \\\\ 3 & 4
\end{matrix} \qquad
\begin{bmatrix}
x_{11} & x_{12} & \ldots & x_{1n}\\
x_{21} & x_{22} & \ldots & x_{2n}\\
\vdots & \vdots & \ddots & \vdots\\
x_{n1} & x_{n2} & \ldots & x_{nn}\\
\end{bmatrix}
$$

$$
\begin{matrix}
1 & 2 \\ 3 & 4
\end{matrix} \qquad
\begin{bmatrix}
x_{11} & x_{12} & \ldots & x_{1n}\\
x_{21} & x_{22} & \ldots & x_{2n}\\
\vdots & \vdots & \ddots & \vdots\\
x_{n1} & x_{n2} & \ldots & x_{nn}\\
\end{bmatrix}
$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$$
\begin{pmatrix}
1 & 2 \\ 3 & 4
\end{pmatrix}
\qquad
\begin{bmatrix}
1 & 2 \\ 3 & 4
\end{bmatrix}
\qquad
\begin{Bmatrix}
1 & 2 \\ 3 & 4
\end{Bmatrix}
\qquad
\begin{vmatrix}
1 & 2 \\ 3 & 4
\end{vmatrix}
\qquad
\begin{Vmatrix}
1 & 2 \\ 3 & 4
\end{Vmatrix}
$$

显示效果:
$$
\begin{pmatrix}
1 & 2 \\ 3 & 4
\end{pmatrix}
\qquad
\begin{bmatrix}
1 & 2 \\ 3 & 4
\end{bmatrix}
\qquad
\begin{Bmatrix}
1 & 2 \\ 3 & 4
\end{Bmatrix}
\qquad
\begin{vmatrix}
1 & 2 \\ 3 & 4
\end{vmatrix}
\qquad
\begin{Vmatrix}
1 & 2 \\ 3 & 4
\end{Vmatrix}
$$

在矩阵中的元素里排版分式时,一来要用到\dfrac等命令,二来行与行之间有可能紧贴着,这时要用到3.6.6小节的方法来调节间距:

1
2
3
4
5
6
7
8
9
10
11
$$
\mathbf{H}=
\begin{bmatrix}
\dfrac{\partial^2 f}{\partial x^2} &
\dfrac{\partial^2 f}
{\partial x \partial y} \\
\dfrac{\partial^2 f}
{\partial x \partial y} &
\dfrac{\partial^2 f}{\partial y^2}
\end{bmatrix}
$$

$$
\mathbf{H}=
\begin{bmatrix}
\dfrac{\partial^2 f}{\partial x^2} &
\dfrac{\partial^2 f}
{\partial x \partial y} \\
\dfrac{\partial^2 f}
{\partial x \partial y} &
\dfrac{\partial^2 f}{\partial y^2}
\end{bmatrix}
$$

数学符号的字体控制

数学字母字体

LATEX允许一部分数学符号切换字体,主要是拉丁字母、数字等等。表4.2给出了切换字体的命令。某一些命令需要字体宏包的支持。

1
2
3
4
5
6
$\mathcal{R} \quad \mathfrak{R}
\quad \mathbb{R}$
$$\mathcal{L}
= -\frac{1}{4}F_{\mu\nu}F^{\mu\nu}$$
$\mathfrak{su}(2)$ and
$\mathfrak{so}(3)$ Lie algebr

$\mathcal{R} \quad \mathfrak{R}
\quad \mathbb{R}$
$$\mathcal{L}
= -\frac{1}{4}F_{\mu\nu}F^{\mu\nu}$$
$\mathfrak{su}(2)$ and
$\mathfrak{so}(3)$ Lie algebr

数学符号的尺寸

数学符号按照符号排版的位置规定尺寸,从大到小包括行间公式尺寸、行内公式尺寸、上下标尺寸、次级上下标尺寸。除了字号有别之外,行间和行内公式尺寸下的巨算符也使用不一样的大小。LATEX为每个数学尺寸指定了一个切换的命令,见4.3。
例如行间公式的分式内,分子分母使用行内公式尺寸,巨算符采用行内尺寸的形式。对比一下分子分母使用\displaystyle命令与否的区别:
这里有一个表格

1
2
3
4
5
6
7
8
$$
P = \frac
{\sum_{i=1}^n (x_i- x)(y_i- y)}
{\displaystyle \left[
\sum_{i=1}^n (x_i-x)^2
\sum_{i=1}^n (y_i-y)^2
\right]^{1/2} }
$$

$$
P = \frac
{\sum_{i=1}^n (x_i- x)(y_i- y)}
{\displaystyle \left[
\sum_{i=1}^n (x_i-x)^2
\sum_{i=1}^n (y_i-y)^2
\right]^{1/2} }
$$

符号表

后面把这些符号表粘贴进来就行了,后面的那些不需要再看了,保留官方文档的连接,现在只要留个印象。

文本/数学模式通用符号

文本/数学模式通用符号 命令
$\{$ {
$\}$ }
$\$$ $
$\%$ %
$\dag$ \dag
$\S$ \S
$\copyright$ \copyright
$\dots$ \dots
$\ddag$ \ddag
$\P$ \P
$\pounds$ \pounds

二元关系符

有的二元关系符都可以加\not前缀得到相反意义的关系符,例如\not=就得到不等号(同\ne)。

效果 命令 效果 命令 效果 命令
$<$ < $>$ > $=$ =
$\leq$ \leq or \le $\ge$ \geq or \ge $\equiv$ \equiv
$\ll$ \ll $\gg$ \gg $\doteq$ \doteq
$\prec$ \prec $\succ$ \succ $\sim$ \sim
$\preceq$ \preceq $\succeq$ \succeq $\simeq$ \simeq
$\subset$ \subset $\supset$ \supset $\approx$ \approx
$\subseteq$ \subseteq $\supseteq$ \supseteq $\cong$ \cong
$\sqsubset$ \sqsubset $\sqsupset$ \sqsupset $\Join$ \Join
$\sqsubseteq$ \sqsubseteq $\sqsupseteq$ \sqsupseteq $\bowtie$ \bowtie
$\in$ \in $\ni$ \ni or \owns $\propto$ \propto
$\vdash$ \vdash $\dashv$ \dashv $\models$ \models
$\mid$ \mid $\parallel$ \parallel $\perp$ \perp
$\smile$ \smile $\frown$ \frown $\asymp$ \asymp
$:$ : $\notin$ \notin $\ne$ \neq or \ne

二元运算符

LaTex中的算符大多数是二元算符,除了直接用键盘可以输入的+,-,*,/外,其他符号用命令输入,常用的符号有乘号:$\times$(\times),除号: $\div$ (\div),点乘: $\cdot$ (\cdot),加减号 $\pm$ (\pm) 或者 $\mp$ (\mp)等等。更多符号命令可参考表4.7以及表4.17

图片内容

渲染效果

latex符号 效果 描述
+ $+$ 加号
- $-$ 减号
\pm $\pm$ 正负号
\mp $\mp$ 正负号
\cdot $\cdot$ 点乘
\times $\times$ 乘法
\div $\div$ 除法
\cup $\cup$
\cap $\cap$ 交集
\sqcup $\sqcup$ 不懂叫啥
\sqcap $\sqcap$ 不懂叫啥
\vee,或者\lor $\vee$,$\lor$ 不懂叫啥
\wedgw,或者\land $\wedge$,$\land$ 不懂叫啥
\oplus $\oplus$ 异或运算
\ominus $\ominus$ 不懂叫啥
\odot $\odot$ 异或运算
\oslash $\oslash$ 不懂叫啥
\otimes $\times$ 不懂叫啥
\bigtriangleup $\bigtriangleup$ 不懂叫啥
\bigtriangledown $\bigtriangledown$ 不懂叫啥
\triangleleft $\triangleleft$ 不懂叫啥
\triangleright $\triangleright$ 不懂叫啥
\star $\star$ 不懂叫啥
\ast $\ast$ 不懂叫啥
\circ $\circ$ 不懂叫啥
\bigcirc $\bigcirc$ 不懂叫啥
\bullet $\bullet$ 不懂叫啥
\diamond $\diamond$ 不懂叫啥
\uplus $\uplus$ 不懂叫啥
\amalg $\amalg$ 不懂叫啥
\dagger $\dagger$ 不懂叫啥
\ddagger $\ddagger$ 不懂叫啥
\wr $\wr$ 不懂叫啥

希腊字母

latex希腊字母符号代码就是斜杠+其英文名称,如$\alpha$:$\alpha$,$\beta$:$\beta$…等。
大写的latex希腊字母就是斜杠+首字母大写的英文名称,如$\Gamma$:$\Gamma$,$\Delta$:$\Delta$…。
\Alpha,\Beta等希腊字母符号不存在,因为它们和拉丁字母A,B等一模一样;小写字母里也不存在\omicron,可以直接用字母o代替,省的打那么长的代码。

希腊字母顺序表

序号 大写 小写 英文 读音
1 $A$ $\alpha$ alpha
2 $B$ $\beta$ beta
3 $\Gamma$ $\gamma$ gamma
4 $\Delta$ $\delta$ delta
5 $E$ $\epsilon$ epsilon
6 $Z$ $\zeta$ zeta
7 $H$ $\eta$ eta
8 $\Theta$ $\theta$ theta
9 $I$ $\iota$ iota
10 $K$ $\kappa$ kappa
11 $\Lambda$ $\lambda$ lambda
12 $M$ $\mu$ mu
13 $N$ $\nu$ nu
14 $\Xi$ $\xi$ xi
15 $O$ $\omicron$ omicron
16 $\Pi$ $\pi$ pi
17 $P$ $\rho$ rho
18 $\Sigma$ $\sigma$ sigma
19 $T$ $\tau$ tau
20 $\Upsilon$ $\upsilon$ upsilon
21 $\Phi$ $\phi$ phi
22 $X$ $\chi$ chi
23 $\Psi$ $\psi$ psi
24 $\Omega$ $\omega$ omega

参考资料

https://baike.baidu.com/item/%E5%B8%8C%E8%85%8A%E5%AD%97%E6%AF%8D/4428067?fr=aladdin#2_1

巨算符

箭头

https://learnku.com/articles/46821
除了作为上下标之外,箭头还用于表示过程。amsmath的\xleftarrow\xrightarrow命令可以为箭头增加上下标:

1
2
$$ a\xleftarrow{x+y+z} b $$
$$ c\xrightarrow[x<y]{a*b*c}d $$

显示效果:
$$
a\xleftarrow{x+y+z} b
$$

$$
c \xrightarrow [x<y]{a*b*c} d
$$

箭头详细表 图片

箭头详细表 渲染

效果 源码 效果 源码
$\leftarrow$或者$\gets$ \leftarrow或者\gets $\longleftarrow$ \longleftarrow
$\rightarrow$或者$\to$ \rightarrow或者\to $\longrightarrow$ \longrightarrow
$\leftrightarrow$ \leftrightarrow $\longleftrightarrow$ \longleftrightarrow
$\Leftarrow$ \Leftarrow $\Longleftarrow$ \Longleftarrow
$\Rightarrow$ \Rightarrow $\Longrightarrow$ \Longrightarrow

括号和定界符

LATEX提供了多种括号和定界符表示公式块的边界。除小括号( )、中括号[ ]之外,其余都是LATEX命令,包括大括号{ }。表4.12和4.13给出了更多的括号/定界符命令。

1
${a,b,c} \neq \{a,b,c\}$

${a,b,c} \neq {a,b,c}$

使用\left和\right命令可令括号(定界符)的大小可变,在行间公式中常用。LATEX会自动根据括号内的公式大小决定定界符大小。\left和\right必须成对使用。需要使用单个定界符时,另一个定界符写成\left.或\right.。

1
2
3
4
\[1 + \left(\frac{1}{1-x^{2}}
\right)^3 \qquad
\left.\frac{\partial f}{\partial t}
\right|_{t=0}\]

$$
1 + \left(\frac{1}{1-x^{2}}
\right)^3 \qquad
\left.\frac{\partial f}{\partial t}
\right|_{t=0}
$$

作为重音的箭头符号

定界符

公式中的间距

参考链接

参考文献: http://texdoc.net/texmf-dist/doc/latex/lshort-chinese/lshort-zh-cn.pdf
参考链接: https://blog.csdn.net/thither_shore/article/details/52260742