Spaces:
Sleeping
Sleeping
Merge branch 'dev'
Browse files- README.md +1 -1
- config.py +19 -11
- crazy_functions/test_project/cpp/longcode/jpgd.cpp +3276 -0
- crazy_functions/test_project/cpp/longcode/jpge.cpp +1049 -0
- crazy_functions/test_project/cpp/longcode/prod_cons.h +433 -0
- crazy_functions/总结word文档.py +127 -0
- crazy_functions/批量总结PDF文档.py +56 -1
- crazy_functions/批量总结PDF文档pdfminer.py +151 -0
- crazy_functions/解析项目源代码.py +4 -3
- crazy_functions/高级功能函数模板.py +2 -2
- functional.py +24 -8
- functional_crazy.py +26 -8
- main.py +70 -40
- predict.py +9 -3
- project_self_analysis.md +119 -66
- requirements.txt +2 -0
- theme.py +12 -0
- toolbox.py +109 -26
README.md
CHANGED
@@ -20,7 +20,7 @@ https://github.com/polarwinkel/mdtex2html
|
|
20 |
|
21 |
> **Note**
|
22 |
>
|
23 |
-
> 1.请注意只有“红颜色”标识的函数插件(按钮)才支持读取文件。目前暂不能完善地支持pdf
|
24 |
>
|
25 |
> 2.本项目中每个文件的功能都在自译解[`project_self_analysis.md`](https://github.com/binary-husky/chatgpt_academic/wiki/chatgpt-academic%E9%A1%B9%E7%9B%AE%E8%87%AA%E8%AF%91%E8%A7%A3%E6%8A%A5%E5%91%8A)详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题汇总在[`wiki`](https://github.com/binary-husky/chatgpt_academic/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)当中。
|
26 |
>
|
|
|
20 |
|
21 |
> **Note**
|
22 |
>
|
23 |
+
> 1.请注意只有“红颜色”标识的函数插件(按钮)才支持读取文件。目前暂不能完善地支持pdf/word格式文献的翻译解读,相关函数函件正在测试中。
|
24 |
>
|
25 |
> 2.本项目中每个文件的功能都在自译解[`project_self_analysis.md`](https://github.com/binary-husky/chatgpt_academic/wiki/chatgpt-academic%E9%A1%B9%E7%9B%AE%E8%87%AA%E8%AF%91%E8%A7%A3%E6%8A%A5%E5%91%8A)详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题汇总在[`wiki`](https://github.com/binary-husky/chatgpt_academic/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)当中。
|
26 |
>
|
config.py
CHANGED
@@ -1,23 +1,28 @@
|
|
1 |
-
# API_KEY = "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"
|
2 |
API_KEY = "sk-此处填API密钥"
|
3 |
-
API_URL = "https://api.openai.com/v1/chat/completions"
|
4 |
|
5 |
-
# 改为True
|
6 |
USE_PROXY = False
|
7 |
if USE_PROXY:
|
8 |
-
|
9 |
-
# 填写格式是 [协议]:// [地址] :[端口] ,
|
10 |
# 例如 "socks5h://localhost:11284"
|
11 |
-
# [协议] 常见协议无非socks5h/http
|
12 |
# [地址] 懂的都懂,不懂就填localhost或者127.0.0.1肯定错不了(localhost意思是代理软件安装在本机上)
|
13 |
-
# [端口]
|
14 |
|
15 |
# 代理网络的地址,打开你的科学上网软件查看代理的协议(socks5/http)、地址(localhost)和端口(11284)
|
16 |
-
proxies = {
|
17 |
-
|
|
|
|
|
|
|
18 |
else:
|
19 |
proxies = None
|
20 |
-
|
|
|
|
|
|
|
|
|
21 |
|
22 |
# 发送请求到OpenAI后,等待多久判定为超时
|
23 |
TIMEOUT_SECONDS = 25
|
@@ -28,9 +33,12 @@ WEB_PORT = -1
|
|
28 |
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
29 |
MAX_RETRY = 2
|
30 |
|
31 |
-
#
|
32 |
LLM_MODEL = "gpt-3.5-turbo"
|
33 |
|
|
|
|
|
|
|
34 |
# 设置并行使用的线程数
|
35 |
CONCURRENT_COUNT = 100
|
36 |
|
|
|
1 |
+
# [step 1]>> 例如: API_KEY = "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" (此key无效)
|
2 |
API_KEY = "sk-此处填API密钥"
|
|
|
3 |
|
4 |
+
# [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改
|
5 |
USE_PROXY = False
|
6 |
if USE_PROXY:
|
7 |
+
# 填写格式是 [协议]:// [地址] :[端口],填写之前不要忘记把USE_PROXY改成True,如果直接在海外服务器部署,此处不修改
|
|
|
8 |
# 例如 "socks5h://localhost:11284"
|
9 |
+
# [协议] 常见协议无非socks5h/http; 例如 v2**y 和 ss* 的默认本地协议是socks5h; 而cl**h 的默认本地协议是http
|
10 |
# [地址] 懂的都懂,不懂就填localhost或者127.0.0.1肯定错不了(localhost意思是代理软件安装在本机上)
|
11 |
+
# [端口] 在代理软件的设置里找。虽然不同的代理软件界面不一样,但端口号都应该在最显眼的位置上
|
12 |
|
13 |
# 代理网络的地址,打开你的科学上网软件查看代理的协议(socks5/http)、地址(localhost)和端口(11284)
|
14 |
+
proxies = {
|
15 |
+
# [协议]:// [地址] :[端口]
|
16 |
+
"http": "socks5h://localhost:11284",
|
17 |
+
"https": "socks5h://localhost:11284",
|
18 |
+
}
|
19 |
else:
|
20 |
proxies = None
|
21 |
+
|
22 |
+
|
23 |
+
# [step 3]>> 以下配置可以优化体验,但大部分场合下并不需要修改
|
24 |
+
# 对话窗的高度
|
25 |
+
CHATBOT_HEIGHT = 1116
|
26 |
|
27 |
# 发送请求到OpenAI后,等待多久判定为超时
|
28 |
TIMEOUT_SECONDS = 25
|
|
|
33 |
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
34 |
MAX_RETRY = 2
|
35 |
|
36 |
+
# OpenAI模型选择是(gpt4现在只对申请成功的人开放)
|
37 |
LLM_MODEL = "gpt-3.5-turbo"
|
38 |
|
39 |
+
# OpenAI的API_URL
|
40 |
+
API_URL = "https://api.openai.com/v1/chat/completions"
|
41 |
+
|
42 |
# 设置并行使用的线程数
|
43 |
CONCURRENT_COUNT = 100
|
44 |
|
crazy_functions/test_project/cpp/longcode/jpgd.cpp
ADDED
@@ -0,0 +1,3276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// jpgd.cpp - C++ class for JPEG decompression.
|
2 |
+
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
3 |
+
// Last updated Apr. 16, 2011
|
4 |
+
// Alex Evans: Linear memory allocator (taken from jpge.h).
|
5 |
+
//
|
6 |
+
// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
|
7 |
+
//
|
8 |
+
// Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling.
|
9 |
+
// Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain"
|
10 |
+
// http://vision.ai.uiuc.edu/~dugad/research/dct/index.html
|
11 |
+
|
12 |
+
#include "jpgd.h"
|
13 |
+
#include <string.h>
|
14 |
+
|
15 |
+
#include <assert.h>
|
16 |
+
// BEGIN EPIC MOD
|
17 |
+
#define JPGD_ASSERT(x) { assert(x); CA_ASSUME(x); } (void)0
|
18 |
+
// END EPIC MOD
|
19 |
+
|
20 |
+
#ifdef _MSC_VER
|
21 |
+
#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
|
22 |
+
#endif
|
23 |
+
|
24 |
+
// Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling).
|
25 |
+
// This is slower, but results in higher quality on images with highly saturated colors.
|
26 |
+
#define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING 1
|
27 |
+
|
28 |
+
#define JPGD_TRUE (1)
|
29 |
+
#define JPGD_FALSE (0)
|
30 |
+
|
31 |
+
#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b))
|
32 |
+
#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b))
|
33 |
+
|
34 |
+
namespace jpgd {
|
35 |
+
|
36 |
+
static inline void *jpgd_malloc(size_t nSize) { return FMemory::Malloc(nSize); }
|
37 |
+
static inline void jpgd_free(void *p) { FMemory::Free(p); }
|
38 |
+
|
39 |
+
// BEGIN EPIC MOD
|
40 |
+
//@UE3 - use UE3 BGRA encoding instead of assuming RGBA
|
41 |
+
// stolen from IImageWrapper.h
|
42 |
+
enum ERGBFormatJPG
|
43 |
+
{
|
44 |
+
Invalid = -1,
|
45 |
+
RGBA = 0,
|
46 |
+
BGRA = 1,
|
47 |
+
Gray = 2,
|
48 |
+
};
|
49 |
+
static ERGBFormatJPG jpg_format;
|
50 |
+
// END EPIC MOD
|
51 |
+
|
52 |
+
// DCT coefficients are stored in this sequence.
|
53 |
+
static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
|
54 |
+
|
55 |
+
enum JPEG_MARKER
|
56 |
+
{
|
57 |
+
M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8,
|
58 |
+
M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC,
|
59 |
+
M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7,
|
60 |
+
M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF,
|
61 |
+
M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0
|
62 |
+
};
|
63 |
+
|
64 |
+
enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 };
|
65 |
+
|
66 |
+
#define CONST_BITS 13
|
67 |
+
#define PASS1_BITS 2
|
68 |
+
#define SCALEDONE ((int32)1)
|
69 |
+
|
70 |
+
#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */
|
71 |
+
#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */
|
72 |
+
#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */
|
73 |
+
#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */
|
74 |
+
#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */
|
75 |
+
#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */
|
76 |
+
#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */
|
77 |
+
#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */
|
78 |
+
#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */
|
79 |
+
#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */
|
80 |
+
#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */
|
81 |
+
#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */
|
82 |
+
|
83 |
+
#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n))
|
84 |
+
#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n))
|
85 |
+
|
86 |
+
#define MULTIPLY(var, cnst) ((var) * (cnst))
|
87 |
+
|
88 |
+
#define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i))
|
89 |
+
|
90 |
+
// Compiler creates a fast path 1D IDCT for X non-zero columns
|
91 |
+
template <int NONZERO_COLS>
|
92 |
+
struct Row
|
93 |
+
{
|
94 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
95 |
+
{
|
96 |
+
// ACCESS_COL() will be optimized at compile time to either an array access, or 0.
|
97 |
+
#define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
|
98 |
+
|
99 |
+
const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6);
|
100 |
+
|
101 |
+
const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
|
102 |
+
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
|
103 |
+
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
|
104 |
+
|
105 |
+
const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS;
|
106 |
+
const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS;
|
107 |
+
|
108 |
+
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
|
109 |
+
|
110 |
+
const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1);
|
111 |
+
|
112 |
+
const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
|
113 |
+
const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
|
114 |
+
|
115 |
+
const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
|
116 |
+
const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
|
117 |
+
const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
|
118 |
+
const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
|
119 |
+
|
120 |
+
const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
|
121 |
+
const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
|
122 |
+
const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
|
123 |
+
const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
|
124 |
+
|
125 |
+
pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS-PASS1_BITS);
|
126 |
+
pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS-PASS1_BITS);
|
127 |
+
pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS-PASS1_BITS);
|
128 |
+
pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS-PASS1_BITS);
|
129 |
+
pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS-PASS1_BITS);
|
130 |
+
pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS-PASS1_BITS);
|
131 |
+
pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS-PASS1_BITS);
|
132 |
+
pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS-PASS1_BITS);
|
133 |
+
}
|
134 |
+
};
|
135 |
+
|
136 |
+
template <>
|
137 |
+
struct Row<0>
|
138 |
+
{
|
139 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
140 |
+
{
|
141 |
+
#ifdef _MSC_VER
|
142 |
+
pTemp; pSrc;
|
143 |
+
#endif
|
144 |
+
}
|
145 |
+
};
|
146 |
+
|
147 |
+
template <>
|
148 |
+
struct Row<1>
|
149 |
+
{
|
150 |
+
static void idct(int* pTemp, const jpgd_block_t* pSrc)
|
151 |
+
{
|
152 |
+
const int dcval = (pSrc[0] << PASS1_BITS);
|
153 |
+
|
154 |
+
pTemp[0] = dcval;
|
155 |
+
pTemp[1] = dcval;
|
156 |
+
pTemp[2] = dcval;
|
157 |
+
pTemp[3] = dcval;
|
158 |
+
pTemp[4] = dcval;
|
159 |
+
pTemp[5] = dcval;
|
160 |
+
pTemp[6] = dcval;
|
161 |
+
pTemp[7] = dcval;
|
162 |
+
}
|
163 |
+
};
|
164 |
+
|
165 |
+
// Compiler creates a fast path 1D IDCT for X non-zero rows
|
166 |
+
template <int NONZERO_ROWS>
|
167 |
+
struct Col
|
168 |
+
{
|
169 |
+
static void idct(uint8* pDst_ptr, const int* pTemp)
|
170 |
+
{
|
171 |
+
// ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
|
172 |
+
#define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
|
173 |
+
|
174 |
+
const int z2 = ACCESS_ROW(2);
|
175 |
+
const int z3 = ACCESS_ROW(6);
|
176 |
+
|
177 |
+
const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
|
178 |
+
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
|
179 |
+
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
|
180 |
+
|
181 |
+
const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS;
|
182 |
+
const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS;
|
183 |
+
|
184 |
+
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
|
185 |
+
|
186 |
+
const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1);
|
187 |
+
|
188 |
+
const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
|
189 |
+
const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
|
190 |
+
|
191 |
+
const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
|
192 |
+
const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
|
193 |
+
const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
|
194 |
+
const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
|
195 |
+
|
196 |
+
const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
|
197 |
+
const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
|
198 |
+
const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
|
199 |
+
const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
|
200 |
+
|
201 |
+
int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS+PASS1_BITS+3);
|
202 |
+
pDst_ptr[8*0] = (uint8)CLAMP(i);
|
203 |
+
|
204 |
+
i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS+PASS1_BITS+3);
|
205 |
+
pDst_ptr[8*7] = (uint8)CLAMP(i);
|
206 |
+
|
207 |
+
i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS+PASS1_BITS+3);
|
208 |
+
pDst_ptr[8*1] = (uint8)CLAMP(i);
|
209 |
+
|
210 |
+
i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS+PASS1_BITS+3);
|
211 |
+
pDst_ptr[8*6] = (uint8)CLAMP(i);
|
212 |
+
|
213 |
+
i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS+PASS1_BITS+3);
|
214 |
+
pDst_ptr[8*2] = (uint8)CLAMP(i);
|
215 |
+
|
216 |
+
i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS+PASS1_BITS+3);
|
217 |
+
pDst_ptr[8*5] = (uint8)CLAMP(i);
|
218 |
+
|
219 |
+
i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS+PASS1_BITS+3);
|
220 |
+
pDst_ptr[8*3] = (uint8)CLAMP(i);
|
221 |
+
|
222 |
+
i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS+PASS1_BITS+3);
|
223 |
+
pDst_ptr[8*4] = (uint8)CLAMP(i);
|
224 |
+
}
|
225 |
+
};
|
226 |
+
|
227 |
+
template <>
|
228 |
+
struct Col<1>
|
229 |
+
{
|
230 |
+
static void idct(uint8* pDst_ptr, const int* pTemp)
|
231 |
+
{
|
232 |
+
int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS+3);
|
233 |
+
const uint8 dcval_clamped = (uint8)CLAMP(dcval);
|
234 |
+
pDst_ptr[0*8] = dcval_clamped;
|
235 |
+
pDst_ptr[1*8] = dcval_clamped;
|
236 |
+
pDst_ptr[2*8] = dcval_clamped;
|
237 |
+
pDst_ptr[3*8] = dcval_clamped;
|
238 |
+
pDst_ptr[4*8] = dcval_clamped;
|
239 |
+
pDst_ptr[5*8] = dcval_clamped;
|
240 |
+
pDst_ptr[6*8] = dcval_clamped;
|
241 |
+
pDst_ptr[7*8] = dcval_clamped;
|
242 |
+
}
|
243 |
+
};
|
244 |
+
|
245 |
+
static const uint8 s_idct_row_table[] =
|
246 |
+
{
|
247 |
+
1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
|
248 |
+
4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
|
249 |
+
6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
|
250 |
+
6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
|
251 |
+
8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
|
252 |
+
8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
|
253 |
+
8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
|
254 |
+
8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
|
255 |
+
};
|
256 |
+
|
257 |
+
static const uint8 s_idct_col_table[] = { 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 };
|
258 |
+
|
259 |
+
void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag)
|
260 |
+
{
|
261 |
+
JPGD_ASSERT(block_max_zag >= 1);
|
262 |
+
JPGD_ASSERT(block_max_zag <= 64);
|
263 |
+
|
264 |
+
if (block_max_zag == 1)
|
265 |
+
{
|
266 |
+
int k = ((pSrc_ptr[0] + 4) >> 3) + 128;
|
267 |
+
k = CLAMP(k);
|
268 |
+
k = k | (k<<8);
|
269 |
+
k = k | (k<<16);
|
270 |
+
|
271 |
+
for (int i = 8; i > 0; i--)
|
272 |
+
{
|
273 |
+
*(int*)&pDst_ptr[0] = k;
|
274 |
+
*(int*)&pDst_ptr[4] = k;
|
275 |
+
pDst_ptr += 8;
|
276 |
+
}
|
277 |
+
return;
|
278 |
+
}
|
279 |
+
|
280 |
+
int temp[64];
|
281 |
+
|
282 |
+
const jpgd_block_t* pSrc = pSrc_ptr;
|
283 |
+
int* pTemp = temp;
|
284 |
+
|
285 |
+
const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8];
|
286 |
+
int i;
|
287 |
+
for (i = 8; i > 0; i--, pRow_tab++)
|
288 |
+
{
|
289 |
+
switch (*pRow_tab)
|
290 |
+
{
|
291 |
+
case 0: Row<0>::idct(pTemp, pSrc); break;
|
292 |
+
case 1: Row<1>::idct(pTemp, pSrc); break;
|
293 |
+
case 2: Row<2>::idct(pTemp, pSrc); break;
|
294 |
+
case 3: Row<3>::idct(pTemp, pSrc); break;
|
295 |
+
case 4: Row<4>::idct(pTemp, pSrc); break;
|
296 |
+
case 5: Row<5>::idct(pTemp, pSrc); break;
|
297 |
+
case 6: Row<6>::idct(pTemp, pSrc); break;
|
298 |
+
case 7: Row<7>::idct(pTemp, pSrc); break;
|
299 |
+
case 8: Row<8>::idct(pTemp, pSrc); break;
|
300 |
+
}
|
301 |
+
|
302 |
+
pSrc += 8;
|
303 |
+
pTemp += 8;
|
304 |
+
}
|
305 |
+
|
306 |
+
pTemp = temp;
|
307 |
+
|
308 |
+
const int nonzero_rows = s_idct_col_table[block_max_zag - 1];
|
309 |
+
for (i = 8; i > 0; i--)
|
310 |
+
{
|
311 |
+
switch (nonzero_rows)
|
312 |
+
{
|
313 |
+
case 1: Col<1>::idct(pDst_ptr, pTemp); break;
|
314 |
+
case 2: Col<2>::idct(pDst_ptr, pTemp); break;
|
315 |
+
case 3: Col<3>::idct(pDst_ptr, pTemp); break;
|
316 |
+
case 4: Col<4>::idct(pDst_ptr, pTemp); break;
|
317 |
+
case 5: Col<5>::idct(pDst_ptr, pTemp); break;
|
318 |
+
case 6: Col<6>::idct(pDst_ptr, pTemp); break;
|
319 |
+
case 7: Col<7>::idct(pDst_ptr, pTemp); break;
|
320 |
+
case 8: Col<8>::idct(pDst_ptr, pTemp); break;
|
321 |
+
}
|
322 |
+
|
323 |
+
pTemp++;
|
324 |
+
pDst_ptr++;
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr)
|
329 |
+
{
|
330 |
+
int temp[64];
|
331 |
+
int* pTemp = temp;
|
332 |
+
const jpgd_block_t* pSrc = pSrc_ptr;
|
333 |
+
|
334 |
+
for (int i = 4; i > 0; i--)
|
335 |
+
{
|
336 |
+
Row<4>::idct(pTemp, pSrc);
|
337 |
+
pSrc += 8;
|
338 |
+
pTemp += 8;
|
339 |
+
}
|
340 |
+
|
341 |
+
pTemp = temp;
|
342 |
+
for (int i = 8; i > 0; i--)
|
343 |
+
{
|
344 |
+
Col<4>::idct(pDst_ptr, pTemp);
|
345 |
+
pTemp++;
|
346 |
+
pDst_ptr++;
|
347 |
+
}
|
348 |
+
}
|
349 |
+
|
350 |
+
// Retrieve one character from the input stream.
|
351 |
+
inline uint jpeg_decoder::get_char()
|
352 |
+
{
|
353 |
+
// Any bytes remaining in buffer?
|
354 |
+
if (!m_in_buf_left)
|
355 |
+
{
|
356 |
+
// Try to get more bytes.
|
357 |
+
prep_in_buffer();
|
358 |
+
// Still nothing to get?
|
359 |
+
if (!m_in_buf_left)
|
360 |
+
{
|
361 |
+
// Pad the end of the stream with 0xFF 0xD9 (EOI marker)
|
362 |
+
int t = m_tem_flag;
|
363 |
+
m_tem_flag ^= 1;
|
364 |
+
if (t)
|
365 |
+
return 0xD9;
|
366 |
+
else
|
367 |
+
return 0xFF;
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
uint c = *m_pIn_buf_ofs++;
|
372 |
+
m_in_buf_left--;
|
373 |
+
|
374 |
+
return c;
|
375 |
+
}
|
376 |
+
|
377 |
+
// Same as previous method, except can indicate if the character is a pad character or not.
|
378 |
+
inline uint jpeg_decoder::get_char(bool *pPadding_flag)
|
379 |
+
{
|
380 |
+
if (!m_in_buf_left)
|
381 |
+
{
|
382 |
+
prep_in_buffer();
|
383 |
+
if (!m_in_buf_left)
|
384 |
+
{
|
385 |
+
*pPadding_flag = true;
|
386 |
+
int t = m_tem_flag;
|
387 |
+
m_tem_flag ^= 1;
|
388 |
+
if (t)
|
389 |
+
return 0xD9;
|
390 |
+
else
|
391 |
+
return 0xFF;
|
392 |
+
}
|
393 |
+
}
|
394 |
+
|
395 |
+
*pPadding_flag = false;
|
396 |
+
|
397 |
+
uint c = *m_pIn_buf_ofs++;
|
398 |
+
m_in_buf_left--;
|
399 |
+
|
400 |
+
return c;
|
401 |
+
}
|
402 |
+
|
403 |
+
// Inserts a previously retrieved character back into the input buffer.
|
404 |
+
inline void jpeg_decoder::stuff_char(uint8 q)
|
405 |
+
{
|
406 |
+
*(--m_pIn_buf_ofs) = q;
|
407 |
+
m_in_buf_left++;
|
408 |
+
}
|
409 |
+
|
410 |
+
// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
|
411 |
+
inline uint8 jpeg_decoder::get_octet()
|
412 |
+
{
|
413 |
+
bool padding_flag;
|
414 |
+
int c = get_char(&padding_flag);
|
415 |
+
|
416 |
+
if (c == 0xFF)
|
417 |
+
{
|
418 |
+
if (padding_flag)
|
419 |
+
return 0xFF;
|
420 |
+
|
421 |
+
c = get_char(&padding_flag);
|
422 |
+
if (padding_flag)
|
423 |
+
{
|
424 |
+
stuff_char(0xFF);
|
425 |
+
return 0xFF;
|
426 |
+
}
|
427 |
+
|
428 |
+
if (c == 0x00)
|
429 |
+
return 0xFF;
|
430 |
+
else
|
431 |
+
{
|
432 |
+
stuff_char(static_cast<uint8>(c));
|
433 |
+
stuff_char(0xFF);
|
434 |
+
return 0xFF;
|
435 |
+
}
|
436 |
+
}
|
437 |
+
|
438 |
+
return static_cast<uint8>(c);
|
439 |
+
}
|
440 |
+
|
441 |
+
// Retrieves a variable number of bits from the input stream. Does not recognize markers.
|
442 |
+
inline uint jpeg_decoder::get_bits(int num_bits)
|
443 |
+
{
|
444 |
+
if (!num_bits)
|
445 |
+
return 0;
|
446 |
+
|
447 |
+
uint i = m_bit_buf >> (32 - num_bits);
|
448 |
+
|
449 |
+
if ((m_bits_left -= num_bits) <= 0)
|
450 |
+
{
|
451 |
+
m_bit_buf <<= (num_bits += m_bits_left);
|
452 |
+
|
453 |
+
uint c1 = get_char();
|
454 |
+
uint c2 = get_char();
|
455 |
+
m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2;
|
456 |
+
|
457 |
+
m_bit_buf <<= -m_bits_left;
|
458 |
+
|
459 |
+
m_bits_left += 16;
|
460 |
+
|
461 |
+
JPGD_ASSERT(m_bits_left >= 0);
|
462 |
+
}
|
463 |
+
else
|
464 |
+
m_bit_buf <<= num_bits;
|
465 |
+
|
466 |
+
return i;
|
467 |
+
}
|
468 |
+
|
469 |
+
// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
|
470 |
+
inline uint jpeg_decoder::get_bits_no_markers(int num_bits)
|
471 |
+
{
|
472 |
+
if (!num_bits)
|
473 |
+
return 0;
|
474 |
+
|
475 |
+
uint i = m_bit_buf >> (32 - num_bits);
|
476 |
+
|
477 |
+
if ((m_bits_left -= num_bits) <= 0)
|
478 |
+
{
|
479 |
+
m_bit_buf <<= (num_bits += m_bits_left);
|
480 |
+
|
481 |
+
if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF))
|
482 |
+
{
|
483 |
+
uint c1 = get_octet();
|
484 |
+
uint c2 = get_octet();
|
485 |
+
m_bit_buf |= (c1 << 8) | c2;
|
486 |
+
}
|
487 |
+
else
|
488 |
+
{
|
489 |
+
m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1];
|
490 |
+
m_in_buf_left -= 2;
|
491 |
+
m_pIn_buf_ofs += 2;
|
492 |
+
}
|
493 |
+
|
494 |
+
m_bit_buf <<= -m_bits_left;
|
495 |
+
|
496 |
+
m_bits_left += 16;
|
497 |
+
|
498 |
+
JPGD_ASSERT(m_bits_left >= 0);
|
499 |
+
}
|
500 |
+
else
|
501 |
+
m_bit_buf <<= num_bits;
|
502 |
+
|
503 |
+
return i;
|
504 |
+
}
|
505 |
+
|
506 |
+
// Decodes a Huffman encoded symbol.
|
507 |
+
inline int jpeg_decoder::huff_decode(huff_tables *pH)
|
508 |
+
{
|
509 |
+
int symbol;
|
510 |
+
|
511 |
+
// Check first 8-bits: do we have a complete symbol?
|
512 |
+
if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0)
|
513 |
+
{
|
514 |
+
// Decode more bits, use a tree traversal to find symbol.
|
515 |
+
int ofs = 23;
|
516 |
+
do
|
517 |
+
{
|
518 |
+
symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
|
519 |
+
ofs--;
|
520 |
+
} while (symbol < 0);
|
521 |
+
|
522 |
+
get_bits_no_markers(8 + (23 - ofs));
|
523 |
+
}
|
524 |
+
else
|
525 |
+
get_bits_no_markers(pH->code_size[symbol]);
|
526 |
+
|
527 |
+
return symbol;
|
528 |
+
}
|
529 |
+
|
530 |
+
// Decodes a Huffman encoded symbol.
|
531 |
+
inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits)
|
532 |
+
{
|
533 |
+
int symbol;
|
534 |
+
|
535 |
+
// Check first 8-bits: do we have a complete symbol?
|
536 |
+
if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0)
|
537 |
+
{
|
538 |
+
// Use a tree traversal to find symbol.
|
539 |
+
int ofs = 23;
|
540 |
+
do
|
541 |
+
{
|
542 |
+
symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
|
543 |
+
ofs--;
|
544 |
+
} while (symbol < 0);
|
545 |
+
|
546 |
+
get_bits_no_markers(8 + (23 - ofs));
|
547 |
+
|
548 |
+
extra_bits = get_bits_no_markers(symbol & 0xF);
|
549 |
+
}
|
550 |
+
else
|
551 |
+
{
|
552 |
+
JPGD_ASSERT(((symbol >> 8) & 31) == pH->code_size[symbol & 255] + ((symbol & 0x8000) ? (symbol & 15) : 0));
|
553 |
+
|
554 |
+
if (symbol & 0x8000)
|
555 |
+
{
|
556 |
+
get_bits_no_markers((symbol >> 8) & 31);
|
557 |
+
extra_bits = symbol >> 16;
|
558 |
+
}
|
559 |
+
else
|
560 |
+
{
|
561 |
+
int code_size = (symbol >> 8) & 31;
|
562 |
+
int num_extra_bits = symbol & 0xF;
|
563 |
+
int bits = code_size + num_extra_bits;
|
564 |
+
if (bits <= (m_bits_left + 16))
|
565 |
+
extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1);
|
566 |
+
else
|
567 |
+
{
|
568 |
+
get_bits_no_markers(code_size);
|
569 |
+
extra_bits = get_bits_no_markers(num_extra_bits);
|
570 |
+
}
|
571 |
+
}
|
572 |
+
|
573 |
+
symbol &= 0xFF;
|
574 |
+
}
|
575 |
+
|
576 |
+
return symbol;
|
577 |
+
}
|
578 |
+
|
579 |
+
// Tables and macro used to fully decode the DPCM differences.
|
580 |
+
static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
|
581 |
+
static const int s_extend_offset[16] = { 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, -4095, -8191, -16383, -32767 };
|
582 |
+
static const int s_extend_mask[] = { 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) };
|
583 |
+
#define HUFF_EXTEND(x,s) ((x) < s_extend_test[s] ? (x) + s_extend_offset[s] : (x))
|
584 |
+
|
585 |
+
// Clamps a value between 0-255.
|
586 |
+
inline uint8 jpeg_decoder::clamp(int i)
|
587 |
+
{
|
588 |
+
if (static_cast<uint>(i) > 255)
|
589 |
+
i = (((~i) >> 31) & 0xFF);
|
590 |
+
|
591 |
+
return static_cast<uint8>(i);
|
592 |
+
}
|
593 |
+
|
594 |
+
namespace DCT_Upsample
|
595 |
+
{
|
596 |
+
struct Matrix44
|
597 |
+
{
|
598 |
+
typedef int Element_Type;
|
599 |
+
enum { NUM_ROWS = 4, NUM_COLS = 4 };
|
600 |
+
|
601 |
+
Element_Type v[NUM_ROWS][NUM_COLS];
|
602 |
+
|
603 |
+
inline int rows() const { return NUM_ROWS; }
|
604 |
+
inline int cols() const { return NUM_COLS; }
|
605 |
+
|
606 |
+
inline const Element_Type & at(int r, int c) const { return v[r][c]; }
|
607 |
+
inline Element_Type & at(int r, int c) { return v[r][c]; }
|
608 |
+
|
609 |
+
inline Matrix44() { }
|
610 |
+
|
611 |
+
inline Matrix44& operator += (const Matrix44& a)
|
612 |
+
{
|
613 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
614 |
+
{
|
615 |
+
at(r, 0) += a.at(r, 0);
|
616 |
+
at(r, 1) += a.at(r, 1);
|
617 |
+
at(r, 2) += a.at(r, 2);
|
618 |
+
at(r, 3) += a.at(r, 3);
|
619 |
+
}
|
620 |
+
return *this;
|
621 |
+
}
|
622 |
+
|
623 |
+
inline Matrix44& operator -= (const Matrix44& a)
|
624 |
+
{
|
625 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
626 |
+
{
|
627 |
+
at(r, 0) -= a.at(r, 0);
|
628 |
+
at(r, 1) -= a.at(r, 1);
|
629 |
+
at(r, 2) -= a.at(r, 2);
|
630 |
+
at(r, 3) -= a.at(r, 3);
|
631 |
+
}
|
632 |
+
return *this;
|
633 |
+
}
|
634 |
+
|
635 |
+
friend inline Matrix44 operator + (const Matrix44& a, const Matrix44& b)
|
636 |
+
{
|
637 |
+
Matrix44 ret;
|
638 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
639 |
+
{
|
640 |
+
ret.at(r, 0) = a.at(r, 0) + b.at(r, 0);
|
641 |
+
ret.at(r, 1) = a.at(r, 1) + b.at(r, 1);
|
642 |
+
ret.at(r, 2) = a.at(r, 2) + b.at(r, 2);
|
643 |
+
ret.at(r, 3) = a.at(r, 3) + b.at(r, 3);
|
644 |
+
}
|
645 |
+
return ret;
|
646 |
+
}
|
647 |
+
|
648 |
+
friend inline Matrix44 operator - (const Matrix44& a, const Matrix44& b)
|
649 |
+
{
|
650 |
+
Matrix44 ret;
|
651 |
+
for (int r = 0; r < NUM_ROWS; r++)
|
652 |
+
{
|
653 |
+
ret.at(r, 0) = a.at(r, 0) - b.at(r, 0);
|
654 |
+
ret.at(r, 1) = a.at(r, 1) - b.at(r, 1);
|
655 |
+
ret.at(r, 2) = a.at(r, 2) - b.at(r, 2);
|
656 |
+
ret.at(r, 3) = a.at(r, 3) - b.at(r, 3);
|
657 |
+
}
|
658 |
+
return ret;
|
659 |
+
}
|
660 |
+
|
661 |
+
static inline void add_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
|
662 |
+
{
|
663 |
+
for (int r = 0; r < 4; r++)
|
664 |
+
{
|
665 |
+
pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) + b.at(r, 0));
|
666 |
+
pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) + b.at(r, 1));
|
667 |
+
pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) + b.at(r, 2));
|
668 |
+
pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) + b.at(r, 3));
|
669 |
+
}
|
670 |
+
}
|
671 |
+
|
672 |
+
static inline void sub_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
|
673 |
+
{
|
674 |
+
for (int r = 0; r < 4; r++)
|
675 |
+
{
|
676 |
+
pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) - b.at(r, 0));
|
677 |
+
pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) - b.at(r, 1));
|
678 |
+
pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) - b.at(r, 2));
|
679 |
+
pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) - b.at(r, 3));
|
680 |
+
}
|
681 |
+
}
|
682 |
+
};
|
683 |
+
|
684 |
+
const int FRACT_BITS = 10;
|
685 |
+
const int SCALE = 1 << FRACT_BITS;
|
686 |
+
|
687 |
+
typedef int Temp_Type;
|
688 |
+
#define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS)
|
689 |
+
#define F(i) ((int)((i) * SCALE + .5f))
|
690 |
+
|
691 |
+
// Any decent C++ compiler will optimize this at compile time to a 0, or an array access.
|
692 |
+
#define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8])
|
693 |
+
|
694 |
+
// NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix
|
695 |
+
template<int NUM_ROWS, int NUM_COLS>
|
696 |
+
struct P_Q
|
697 |
+
{
|
698 |
+
static void calc(Matrix44& P, Matrix44& Q, const jpgd_block_t* pSrc)
|
699 |
+
{
|
700 |
+
// 4x8 = 4x8 times 8x8, matrix 0 is constant
|
701 |
+
const Temp_Type X000 = AT(0, 0);
|
702 |
+
const Temp_Type X001 = AT(0, 1);
|
703 |
+
const Temp_Type X002 = AT(0, 2);
|
704 |
+
const Temp_Type X003 = AT(0, 3);
|
705 |
+
const Temp_Type X004 = AT(0, 4);
|
706 |
+
const Temp_Type X005 = AT(0, 5);
|
707 |
+
const Temp_Type X006 = AT(0, 6);
|
708 |
+
const Temp_Type X007 = AT(0, 7);
|
709 |
+
const Temp_Type X010 = D(F(0.415735f) * AT(1, 0) + F(0.791065f) * AT(3, 0) + F(-0.352443f) * AT(5, 0) + F(0.277785f) * AT(7, 0));
|
710 |
+
const Temp_Type X011 = D(F(0.415735f) * AT(1, 1) + F(0.791065f) * AT(3, 1) + F(-0.352443f) * AT(5, 1) + F(0.277785f) * AT(7, 1));
|
711 |
+
const Temp_Type X012 = D(F(0.415735f) * AT(1, 2) + F(0.791065f) * AT(3, 2) + F(-0.352443f) * AT(5, 2) + F(0.277785f) * AT(7, 2));
|
712 |
+
const Temp_Type X013 = D(F(0.415735f) * AT(1, 3) + F(0.791065f) * AT(3, 3) + F(-0.352443f) * AT(5, 3) + F(0.277785f) * AT(7, 3));
|
713 |
+
const Temp_Type X014 = D(F(0.415735f) * AT(1, 4) + F(0.791065f) * AT(3, 4) + F(-0.352443f) * AT(5, 4) + F(0.277785f) * AT(7, 4));
|
714 |
+
const Temp_Type X015 = D(F(0.415735f) * AT(1, 5) + F(0.791065f) * AT(3, 5) + F(-0.352443f) * AT(5, 5) + F(0.277785f) * AT(7, 5));
|
715 |
+
const Temp_Type X016 = D(F(0.415735f) * AT(1, 6) + F(0.791065f) * AT(3, 6) + F(-0.352443f) * AT(5, 6) + F(0.277785f) * AT(7, 6));
|
716 |
+
const Temp_Type X017 = D(F(0.415735f) * AT(1, 7) + F(0.791065f) * AT(3, 7) + F(-0.352443f) * AT(5, 7) + F(0.277785f) * AT(7, 7));
|
717 |
+
const Temp_Type X020 = AT(4, 0);
|
718 |
+
const Temp_Type X021 = AT(4, 1);
|
719 |
+
const Temp_Type X022 = AT(4, 2);
|
720 |
+
const Temp_Type X023 = AT(4, 3);
|
721 |
+
const Temp_Type X024 = AT(4, 4);
|
722 |
+
const Temp_Type X025 = AT(4, 5);
|
723 |
+
const Temp_Type X026 = AT(4, 6);
|
724 |
+
const Temp_Type X027 = AT(4, 7);
|
725 |
+
const Temp_Type X030 = D(F(0.022887f) * AT(1, 0) + F(-0.097545f) * AT(3, 0) + F(0.490393f) * AT(5, 0) + F(0.865723f) * AT(7, 0));
|
726 |
+
const Temp_Type X031 = D(F(0.022887f) * AT(1, 1) + F(-0.097545f) * AT(3, 1) + F(0.490393f) * AT(5, 1) + F(0.865723f) * AT(7, 1));
|
727 |
+
const Temp_Type X032 = D(F(0.022887f) * AT(1, 2) + F(-0.097545f) * AT(3, 2) + F(0.490393f) * AT(5, 2) + F(0.865723f) * AT(7, 2));
|
728 |
+
const Temp_Type X033 = D(F(0.022887f) * AT(1, 3) + F(-0.097545f) * AT(3, 3) + F(0.490393f) * AT(5, 3) + F(0.865723f) * AT(7, 3));
|
729 |
+
const Temp_Type X034 = D(F(0.022887f) * AT(1, 4) + F(-0.097545f) * AT(3, 4) + F(0.490393f) * AT(5, 4) + F(0.865723f) * AT(7, 4));
|
730 |
+
const Temp_Type X035 = D(F(0.022887f) * AT(1, 5) + F(-0.097545f) * AT(3, 5) + F(0.490393f) * AT(5, 5) + F(0.865723f) * AT(7, 5));
|
731 |
+
const Temp_Type X036 = D(F(0.022887f) * AT(1, 6) + F(-0.097545f) * AT(3, 6) + F(0.490393f) * AT(5, 6) + F(0.865723f) * AT(7, 6));
|
732 |
+
const Temp_Type X037 = D(F(0.022887f) * AT(1, 7) + F(-0.097545f) * AT(3, 7) + F(0.490393f) * AT(5, 7) + F(0.865723f) * AT(7, 7));
|
733 |
+
|
734 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
735 |
+
P.at(0, 0) = X000;
|
736 |
+
P.at(0, 1) = D(X001 * F(0.415735f) + X003 * F(0.791065f) + X005 * F(-0.352443f) + X007 * F(0.277785f));
|
737 |
+
P.at(0, 2) = X004;
|
738 |
+
P.at(0, 3) = D(X001 * F(0.022887f) + X003 * F(-0.097545f) + X005 * F(0.490393f) + X007 * F(0.865723f));
|
739 |
+
P.at(1, 0) = X010;
|
740 |
+
P.at(1, 1) = D(X011 * F(0.415735f) + X013 * F(0.791065f) + X015 * F(-0.352443f) + X017 * F(0.277785f));
|
741 |
+
P.at(1, 2) = X014;
|
742 |
+
P.at(1, 3) = D(X011 * F(0.022887f) + X013 * F(-0.097545f) + X015 * F(0.490393f) + X017 * F(0.865723f));
|
743 |
+
P.at(2, 0) = X020;
|
744 |
+
P.at(2, 1) = D(X021 * F(0.415735f) + X023 * F(0.791065f) + X025 * F(-0.352443f) + X027 * F(0.277785f));
|
745 |
+
P.at(2, 2) = X024;
|
746 |
+
P.at(2, 3) = D(X021 * F(0.022887f) + X023 * F(-0.097545f) + X025 * F(0.490393f) + X027 * F(0.865723f));
|
747 |
+
P.at(3, 0) = X030;
|
748 |
+
P.at(3, 1) = D(X031 * F(0.415735f) + X033 * F(0.791065f) + X035 * F(-0.352443f) + X037 * F(0.277785f));
|
749 |
+
P.at(3, 2) = X034;
|
750 |
+
P.at(3, 3) = D(X031 * F(0.022887f) + X033 * F(-0.097545f) + X035 * F(0.490393f) + X037 * F(0.865723f));
|
751 |
+
// 40 muls 24 adds
|
752 |
+
|
753 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
754 |
+
Q.at(0, 0) = D(X001 * F(0.906127f) + X003 * F(-0.318190f) + X005 * F(0.212608f) + X007 * F(-0.180240f));
|
755 |
+
Q.at(0, 1) = X002;
|
756 |
+
Q.at(0, 2) = D(X001 * F(-0.074658f) + X003 * F(0.513280f) + X005 * F(0.768178f) + X007 * F(-0.375330f));
|
757 |
+
Q.at(0, 3) = X006;
|
758 |
+
Q.at(1, 0) = D(X011 * F(0.906127f) + X013 * F(-0.318190f) + X015 * F(0.212608f) + X017 * F(-0.180240f));
|
759 |
+
Q.at(1, 1) = X012;
|
760 |
+
Q.at(1, 2) = D(X011 * F(-0.074658f) + X013 * F(0.513280f) + X015 * F(0.768178f) + X017 * F(-0.375330f));
|
761 |
+
Q.at(1, 3) = X016;
|
762 |
+
Q.at(2, 0) = D(X021 * F(0.906127f) + X023 * F(-0.318190f) + X025 * F(0.212608f) + X027 * F(-0.180240f));
|
763 |
+
Q.at(2, 1) = X022;
|
764 |
+
Q.at(2, 2) = D(X021 * F(-0.074658f) + X023 * F(0.513280f) + X025 * F(0.768178f) + X027 * F(-0.375330f));
|
765 |
+
Q.at(2, 3) = X026;
|
766 |
+
Q.at(3, 0) = D(X031 * F(0.906127f) + X033 * F(-0.318190f) + X035 * F(0.212608f) + X037 * F(-0.180240f));
|
767 |
+
Q.at(3, 1) = X032;
|
768 |
+
Q.at(3, 2) = D(X031 * F(-0.074658f) + X033 * F(0.513280f) + X035 * F(0.768178f) + X037 * F(-0.375330f));
|
769 |
+
Q.at(3, 3) = X036;
|
770 |
+
// 40 muls 24 adds
|
771 |
+
}
|
772 |
+
};
|
773 |
+
|
774 |
+
template<int NUM_ROWS, int NUM_COLS>
|
775 |
+
struct R_S
|
776 |
+
{
|
777 |
+
static void calc(Matrix44& R, Matrix44& S, const jpgd_block_t* pSrc)
|
778 |
+
{
|
779 |
+
// 4x8 = 4x8 times 8x8, matrix 0 is constant
|
780 |
+
const Temp_Type X100 = D(F(0.906127f) * AT(1, 0) + F(-0.318190f) * AT(3, 0) + F(0.212608f) * AT(5, 0) + F(-0.180240f) * AT(7, 0));
|
781 |
+
const Temp_Type X101 = D(F(0.906127f) * AT(1, 1) + F(-0.318190f) * AT(3, 1) + F(0.212608f) * AT(5, 1) + F(-0.180240f) * AT(7, 1));
|
782 |
+
const Temp_Type X102 = D(F(0.906127f) * AT(1, 2) + F(-0.318190f) * AT(3, 2) + F(0.212608f) * AT(5, 2) + F(-0.180240f) * AT(7, 2));
|
783 |
+
const Temp_Type X103 = D(F(0.906127f) * AT(1, 3) + F(-0.318190f) * AT(3, 3) + F(0.212608f) * AT(5, 3) + F(-0.180240f) * AT(7, 3));
|
784 |
+
const Temp_Type X104 = D(F(0.906127f) * AT(1, 4) + F(-0.318190f) * AT(3, 4) + F(0.212608f) * AT(5, 4) + F(-0.180240f) * AT(7, 4));
|
785 |
+
const Temp_Type X105 = D(F(0.906127f) * AT(1, 5) + F(-0.318190f) * AT(3, 5) + F(0.212608f) * AT(5, 5) + F(-0.180240f) * AT(7, 5));
|
786 |
+
const Temp_Type X106 = D(F(0.906127f) * AT(1, 6) + F(-0.318190f) * AT(3, 6) + F(0.212608f) * AT(5, 6) + F(-0.180240f) * AT(7, 6));
|
787 |
+
const Temp_Type X107 = D(F(0.906127f) * AT(1, 7) + F(-0.318190f) * AT(3, 7) + F(0.212608f) * AT(5, 7) + F(-0.180240f) * AT(7, 7));
|
788 |
+
const Temp_Type X110 = AT(2, 0);
|
789 |
+
const Temp_Type X111 = AT(2, 1);
|
790 |
+
const Temp_Type X112 = AT(2, 2);
|
791 |
+
const Temp_Type X113 = AT(2, 3);
|
792 |
+
const Temp_Type X114 = AT(2, 4);
|
793 |
+
const Temp_Type X115 = AT(2, 5);
|
794 |
+
const Temp_Type X116 = AT(2, 6);
|
795 |
+
const Temp_Type X117 = AT(2, 7);
|
796 |
+
const Temp_Type X120 = D(F(-0.074658f) * AT(1, 0) + F(0.513280f) * AT(3, 0) + F(0.768178f) * AT(5, 0) + F(-0.375330f) * AT(7, 0));
|
797 |
+
const Temp_Type X121 = D(F(-0.074658f) * AT(1, 1) + F(0.513280f) * AT(3, 1) + F(0.768178f) * AT(5, 1) + F(-0.375330f) * AT(7, 1));
|
798 |
+
const Temp_Type X122 = D(F(-0.074658f) * AT(1, 2) + F(0.513280f) * AT(3, 2) + F(0.768178f) * AT(5, 2) + F(-0.375330f) * AT(7, 2));
|
799 |
+
const Temp_Type X123 = D(F(-0.074658f) * AT(1, 3) + F(0.513280f) * AT(3, 3) + F(0.768178f) * AT(5, 3) + F(-0.375330f) * AT(7, 3));
|
800 |
+
const Temp_Type X124 = D(F(-0.074658f) * AT(1, 4) + F(0.513280f) * AT(3, 4) + F(0.768178f) * AT(5, 4) + F(-0.375330f) * AT(7, 4));
|
801 |
+
const Temp_Type X125 = D(F(-0.074658f) * AT(1, 5) + F(0.513280f) * AT(3, 5) + F(0.768178f) * AT(5, 5) + F(-0.375330f) * AT(7, 5));
|
802 |
+
const Temp_Type X126 = D(F(-0.074658f) * AT(1, 6) + F(0.513280f) * AT(3, 6) + F(0.768178f) * AT(5, 6) + F(-0.375330f) * AT(7, 6));
|
803 |
+
const Temp_Type X127 = D(F(-0.074658f) * AT(1, 7) + F(0.513280f) * AT(3, 7) + F(0.768178f) * AT(5, 7) + F(-0.375330f) * AT(7, 7));
|
804 |
+
const Temp_Type X130 = AT(6, 0);
|
805 |
+
const Temp_Type X131 = AT(6, 1);
|
806 |
+
const Temp_Type X132 = AT(6, 2);
|
807 |
+
const Temp_Type X133 = AT(6, 3);
|
808 |
+
const Temp_Type X134 = AT(6, 4);
|
809 |
+
const Temp_Type X135 = AT(6, 5);
|
810 |
+
const Temp_Type X136 = AT(6, 6);
|
811 |
+
const Temp_Type X137 = AT(6, 7);
|
812 |
+
// 80 muls 48 adds
|
813 |
+
|
814 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
815 |
+
R.at(0, 0) = X100;
|
816 |
+
R.at(0, 1) = D(X101 * F(0.415735f) + X103 * F(0.791065f) + X105 * F(-0.352443f) + X107 * F(0.277785f));
|
817 |
+
R.at(0, 2) = X104;
|
818 |
+
R.at(0, 3) = D(X101 * F(0.022887f) + X103 * F(-0.097545f) + X105 * F(0.490393f) + X107 * F(0.865723f));
|
819 |
+
R.at(1, 0) = X110;
|
820 |
+
R.at(1, 1) = D(X111 * F(0.415735f) + X113 * F(0.791065f) + X115 * F(-0.352443f) + X117 * F(0.277785f));
|
821 |
+
R.at(1, 2) = X114;
|
822 |
+
R.at(1, 3) = D(X111 * F(0.022887f) + X113 * F(-0.097545f) + X115 * F(0.490393f) + X117 * F(0.865723f));
|
823 |
+
R.at(2, 0) = X120;
|
824 |
+
R.at(2, 1) = D(X121 * F(0.415735f) + X123 * F(0.791065f) + X125 * F(-0.352443f) + X127 * F(0.277785f));
|
825 |
+
R.at(2, 2) = X124;
|
826 |
+
R.at(2, 3) = D(X121 * F(0.022887f) + X123 * F(-0.097545f) + X125 * F(0.490393f) + X127 * F(0.865723f));
|
827 |
+
R.at(3, 0) = X130;
|
828 |
+
R.at(3, 1) = D(X131 * F(0.415735f) + X133 * F(0.791065f) + X135 * F(-0.352443f) + X137 * F(0.277785f));
|
829 |
+
R.at(3, 2) = X134;
|
830 |
+
R.at(3, 3) = D(X131 * F(0.022887f) + X133 * F(-0.097545f) + X135 * F(0.490393f) + X137 * F(0.865723f));
|
831 |
+
// 40 muls 24 adds
|
832 |
+
// 4x4 = 4x8 times 8x4, matrix 1 is constant
|
833 |
+
S.at(0, 0) = D(X101 * F(0.906127f) + X103 * F(-0.318190f) + X105 * F(0.212608f) + X107 * F(-0.180240f));
|
834 |
+
S.at(0, 1) = X102;
|
835 |
+
S.at(0, 2) = D(X101 * F(-0.074658f) + X103 * F(0.513280f) + X105 * F(0.768178f) + X107 * F(-0.375330f));
|
836 |
+
S.at(0, 3) = X106;
|
837 |
+
S.at(1, 0) = D(X111 * F(0.906127f) + X113 * F(-0.318190f) + X115 * F(0.212608f) + X117 * F(-0.180240f));
|
838 |
+
S.at(1, 1) = X112;
|
839 |
+
S.at(1, 2) = D(X111 * F(-0.074658f) + X113 * F(0.513280f) + X115 * F(0.768178f) + X117 * F(-0.375330f));
|
840 |
+
S.at(1, 3) = X116;
|
841 |
+
S.at(2, 0) = D(X121 * F(0.906127f) + X123 * F(-0.318190f) + X125 * F(0.212608f) + X127 * F(-0.180240f));
|
842 |
+
S.at(2, 1) = X122;
|
843 |
+
S.at(2, 2) = D(X121 * F(-0.074658f) + X123 * F(0.513280f) + X125 * F(0.768178f) + X127 * F(-0.375330f));
|
844 |
+
S.at(2, 3) = X126;
|
845 |
+
S.at(3, 0) = D(X131 * F(0.906127f) + X133 * F(-0.318190f) + X135 * F(0.212608f) + X137 * F(-0.180240f));
|
846 |
+
S.at(3, 1) = X132;
|
847 |
+
S.at(3, 2) = D(X131 * F(-0.074658f) + X133 * F(0.513280f) + X135 * F(0.768178f) + X137 * F(-0.375330f));
|
848 |
+
S.at(3, 3) = X136;
|
849 |
+
// 40 muls 24 adds
|
850 |
+
}
|
851 |
+
};
|
852 |
+
} // end namespace DCT_Upsample
|
853 |
+
|
854 |
+
// Unconditionally frees all allocated m_blocks.
|
855 |
+
void jpeg_decoder::free_all_blocks()
|
856 |
+
{
|
857 |
+
m_pStream = NULL;
|
858 |
+
for (mem_block *b = m_pMem_blocks; b; )
|
859 |
+
{
|
860 |
+
mem_block *n = b->m_pNext;
|
861 |
+
jpgd_free(b);
|
862 |
+
b = n;
|
863 |
+
}
|
864 |
+
m_pMem_blocks = NULL;
|
865 |
+
}
|
866 |
+
|
867 |
+
// This method handles all errors.
|
868 |
+
// It could easily be changed to use C++ exceptions.
|
869 |
+
void jpeg_decoder::stop_decoding(jpgd_status status)
|
870 |
+
{
|
871 |
+
m_error_code = status;
|
872 |
+
free_all_blocks();
|
873 |
+
longjmp(m_jmp_state, status);
|
874 |
+
|
875 |
+
// we shouldn't get here as longjmp shouldn't return, but we put it here to make it explicit
|
876 |
+
// that this function doesn't return, otherwise we get this error:
|
877 |
+
//
|
878 |
+
// error : function declared 'noreturn' should not return
|
879 |
+
exit(1);
|
880 |
+
}
|
881 |
+
|
882 |
+
void *jpeg_decoder::alloc(size_t nSize, bool zero)
|
883 |
+
{
|
884 |
+
nSize = (JPGD_MAX(nSize, 1) + 3) & ~3;
|
885 |
+
char *rv = NULL;
|
886 |
+
for (mem_block *b = m_pMem_blocks; b; b = b->m_pNext)
|
887 |
+
{
|
888 |
+
if ((b->m_used_count + nSize) <= b->m_size)
|
889 |
+
{
|
890 |
+
rv = b->m_data + b->m_used_count;
|
891 |
+
b->m_used_count += nSize;
|
892 |
+
break;
|
893 |
+
}
|
894 |
+
}
|
895 |
+
if (!rv)
|
896 |
+
{
|
897 |
+
int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047);
|
898 |
+
mem_block *b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity);
|
899 |
+
if (!b) stop_decoding(JPGD_NOTENOUGHMEM);
|
900 |
+
b->m_pNext = m_pMem_blocks; m_pMem_blocks = b;
|
901 |
+
b->m_used_count = nSize;
|
902 |
+
b->m_size = capacity;
|
903 |
+
rv = b->m_data;
|
904 |
+
}
|
905 |
+
if (zero) memset(rv, 0, nSize);
|
906 |
+
return rv;
|
907 |
+
}
|
908 |
+
|
909 |
+
void jpeg_decoder::word_clear(void *p, uint16 c, uint n)
|
910 |
+
{
|
911 |
+
uint8 *pD = (uint8*)p;
|
912 |
+
const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF;
|
913 |
+
while (n)
|
914 |
+
{
|
915 |
+
pD[0] = l; pD[1] = h; pD += 2;
|
916 |
+
n--;
|
917 |
+
}
|
918 |
+
}
|
919 |
+
|
920 |
+
// Refill the input buffer.
|
921 |
+
// This method will sit in a loop until (A) the buffer is full or (B)
|
922 |
+
// the stream's read() method reports and end of file condition.
|
923 |
+
void jpeg_decoder::prep_in_buffer()
|
924 |
+
{
|
925 |
+
m_in_buf_left = 0;
|
926 |
+
m_pIn_buf_ofs = m_in_buf;
|
927 |
+
|
928 |
+
if (m_eof_flag)
|
929 |
+
return;
|
930 |
+
|
931 |
+
do
|
932 |
+
{
|
933 |
+
int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag);
|
934 |
+
if (bytes_read == -1)
|
935 |
+
stop_decoding(JPGD_STREAM_READ);
|
936 |
+
|
937 |
+
m_in_buf_left += bytes_read;
|
938 |
+
} while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag));
|
939 |
+
|
940 |
+
m_total_bytes_read += m_in_buf_left;
|
941 |
+
|
942 |
+
// Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
|
943 |
+
// (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
|
944 |
+
word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64);
|
945 |
+
}
|
946 |
+
|
947 |
+
// Read a Huffman code table.
|
948 |
+
void jpeg_decoder::read_dht_marker()
|
949 |
+
{
|
950 |
+
int i, index, count;
|
951 |
+
uint8 huff_num[17];
|
952 |
+
uint8 huff_val[256];
|
953 |
+
|
954 |
+
uint num_left = get_bits(16);
|
955 |
+
|
956 |
+
if (num_left < 2)
|
957 |
+
stop_decoding(JPGD_BAD_DHT_MARKER);
|
958 |
+
|
959 |
+
num_left -= 2;
|
960 |
+
|
961 |
+
while (num_left)
|
962 |
+
{
|
963 |
+
index = get_bits(8);
|
964 |
+
|
965 |
+
huff_num[0] = 0;
|
966 |
+
|
967 |
+
count = 0;
|
968 |
+
|
969 |
+
for (i = 1; i <= 16; i++)
|
970 |
+
{
|
971 |
+
huff_num[i] = static_cast<uint8>(get_bits(8));
|
972 |
+
count += huff_num[i];
|
973 |
+
}
|
974 |
+
|
975 |
+
if (count > 255)
|
976 |
+
stop_decoding(JPGD_BAD_DHT_COUNTS);
|
977 |
+
|
978 |
+
for (i = 0; i < count; i++)
|
979 |
+
huff_val[i] = static_cast<uint8>(get_bits(8));
|
980 |
+
|
981 |
+
i = 1 + 16 + count;
|
982 |
+
|
983 |
+
if (num_left < (uint)i)
|
984 |
+
stop_decoding(JPGD_BAD_DHT_MARKER);
|
985 |
+
|
986 |
+
num_left -= i;
|
987 |
+
|
988 |
+
if ((index & 0x10) > 0x10)
|
989 |
+
stop_decoding(JPGD_BAD_DHT_INDEX);
|
990 |
+
|
991 |
+
index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1);
|
992 |
+
|
993 |
+
if (index >= JPGD_MAX_HUFF_TABLES)
|
994 |
+
stop_decoding(JPGD_BAD_DHT_INDEX);
|
995 |
+
|
996 |
+
if (!m_huff_num[index])
|
997 |
+
m_huff_num[index] = (uint8 *)alloc(17);
|
998 |
+
|
999 |
+
if (!m_huff_val[index])
|
1000 |
+
m_huff_val[index] = (uint8 *)alloc(256);
|
1001 |
+
|
1002 |
+
m_huff_ac[index] = (index & 0x10) != 0;
|
1003 |
+
memcpy(m_huff_num[index], huff_num, 17);
|
1004 |
+
memcpy(m_huff_val[index], huff_val, 256);
|
1005 |
+
}
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
// Read a quantization table.
|
1009 |
+
void jpeg_decoder::read_dqt_marker()
|
1010 |
+
{
|
1011 |
+
int n, i, prec;
|
1012 |
+
uint num_left;
|
1013 |
+
uint temp;
|
1014 |
+
|
1015 |
+
num_left = get_bits(16);
|
1016 |
+
|
1017 |
+
if (num_left < 2)
|
1018 |
+
stop_decoding(JPGD_BAD_DQT_MARKER);
|
1019 |
+
|
1020 |
+
num_left -= 2;
|
1021 |
+
|
1022 |
+
while (num_left)
|
1023 |
+
{
|
1024 |
+
n = get_bits(8);
|
1025 |
+
prec = n >> 4;
|
1026 |
+
n &= 0x0F;
|
1027 |
+
|
1028 |
+
if (n >= JPGD_MAX_QUANT_TABLES)
|
1029 |
+
stop_decoding(JPGD_BAD_DQT_TABLE);
|
1030 |
+
|
1031 |
+
if (!m_quant[n])
|
1032 |
+
m_quant[n] = (jpgd_quant_t *)alloc(64 * sizeof(jpgd_quant_t));
|
1033 |
+
|
1034 |
+
// read quantization entries, in zag order
|
1035 |
+
for (i = 0; i < 64; i++)
|
1036 |
+
{
|
1037 |
+
temp = get_bits(8);
|
1038 |
+
|
1039 |
+
if (prec)
|
1040 |
+
temp = (temp << 8) + get_bits(8);
|
1041 |
+
|
1042 |
+
m_quant[n][i] = static_cast<jpgd_quant_t>(temp);
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
i = 64 + 1;
|
1046 |
+
|
1047 |
+
if (prec)
|
1048 |
+
i += 64;
|
1049 |
+
|
1050 |
+
if (num_left < (uint)i)
|
1051 |
+
stop_decoding(JPGD_BAD_DQT_LENGTH);
|
1052 |
+
|
1053 |
+
num_left -= i;
|
1054 |
+
}
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
// Read the start of frame (SOF) marker.
|
1058 |
+
void jpeg_decoder::read_sof_marker()
|
1059 |
+
{
|
1060 |
+
int i;
|
1061 |
+
uint num_left;
|
1062 |
+
|
1063 |
+
num_left = get_bits(16);
|
1064 |
+
|
1065 |
+
if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */
|
1066 |
+
stop_decoding(JPGD_BAD_PRECISION);
|
1067 |
+
|
1068 |
+
m_image_y_size = get_bits(16);
|
1069 |
+
|
1070 |
+
if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT))
|
1071 |
+
stop_decoding(JPGD_BAD_HEIGHT);
|
1072 |
+
|
1073 |
+
m_image_x_size = get_bits(16);
|
1074 |
+
|
1075 |
+
if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH))
|
1076 |
+
stop_decoding(JPGD_BAD_WIDTH);
|
1077 |
+
|
1078 |
+
m_comps_in_frame = get_bits(8);
|
1079 |
+
|
1080 |
+
if (m_comps_in_frame > JPGD_MAX_COMPONENTS)
|
1081 |
+
stop_decoding(JPGD_TOO_MANY_COMPONENTS);
|
1082 |
+
|
1083 |
+
if (num_left != (uint)(m_comps_in_frame * 3 + 8))
|
1084 |
+
stop_decoding(JPGD_BAD_SOF_LENGTH);
|
1085 |
+
|
1086 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
1087 |
+
{
|
1088 |
+
m_comp_ident[i] = get_bits(8);
|
1089 |
+
m_comp_h_samp[i] = get_bits(4);
|
1090 |
+
m_comp_v_samp[i] = get_bits(4);
|
1091 |
+
m_comp_quant[i] = get_bits(8);
|
1092 |
+
}
|
1093 |
+
}
|
1094 |
+
|
1095 |
+
// Used to skip unrecognized markers.
|
1096 |
+
void jpeg_decoder::skip_variable_marker()
|
1097 |
+
{
|
1098 |
+
uint num_left;
|
1099 |
+
|
1100 |
+
num_left = get_bits(16);
|
1101 |
+
|
1102 |
+
if (num_left < 2)
|
1103 |
+
stop_decoding(JPGD_BAD_VARIABLE_MARKER);
|
1104 |
+
|
1105 |
+
num_left -= 2;
|
1106 |
+
|
1107 |
+
while (num_left)
|
1108 |
+
{
|
1109 |
+
get_bits(8);
|
1110 |
+
num_left--;
|
1111 |
+
}
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
// Read a define restart interval (DRI) marker.
|
1115 |
+
void jpeg_decoder::read_dri_marker()
|
1116 |
+
{
|
1117 |
+
if (get_bits(16) != 4)
|
1118 |
+
stop_decoding(JPGD_BAD_DRI_LENGTH);
|
1119 |
+
|
1120 |
+
m_restart_interval = get_bits(16);
|
1121 |
+
}
|
1122 |
+
|
1123 |
+
// Read a start of scan (SOS) marker.
|
1124 |
+
void jpeg_decoder::read_sos_marker()
|
1125 |
+
{
|
1126 |
+
uint num_left;
|
1127 |
+
int i, ci, n, c, cc;
|
1128 |
+
|
1129 |
+
num_left = get_bits(16);
|
1130 |
+
|
1131 |
+
n = get_bits(8);
|
1132 |
+
|
1133 |
+
m_comps_in_scan = n;
|
1134 |
+
|
1135 |
+
num_left -= 3;
|
1136 |
+
|
1137 |
+
if ( (num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) )
|
1138 |
+
stop_decoding(JPGD_BAD_SOS_LENGTH);
|
1139 |
+
|
1140 |
+
for (i = 0; i < n; i++)
|
1141 |
+
{
|
1142 |
+
cc = get_bits(8);
|
1143 |
+
c = get_bits(8);
|
1144 |
+
num_left -= 2;
|
1145 |
+
|
1146 |
+
for (ci = 0; ci < m_comps_in_frame; ci++)
|
1147 |
+
if (cc == m_comp_ident[ci])
|
1148 |
+
break;
|
1149 |
+
|
1150 |
+
if (ci >= m_comps_in_frame)
|
1151 |
+
stop_decoding(JPGD_BAD_SOS_COMP_ID);
|
1152 |
+
|
1153 |
+
m_comp_list[i] = ci;
|
1154 |
+
m_comp_dc_tab[ci] = (c >> 4) & 15;
|
1155 |
+
m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1);
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
m_spectral_start = get_bits(8);
|
1159 |
+
m_spectral_end = get_bits(8);
|
1160 |
+
m_successive_high = get_bits(4);
|
1161 |
+
m_successive_low = get_bits(4);
|
1162 |
+
|
1163 |
+
if (!m_progressive_flag)
|
1164 |
+
{
|
1165 |
+
m_spectral_start = 0;
|
1166 |
+
m_spectral_end = 63;
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
num_left -= 3;
|
1170 |
+
|
1171 |
+
while (num_left) /* read past whatever is num_left */
|
1172 |
+
{
|
1173 |
+
get_bits(8);
|
1174 |
+
num_left--;
|
1175 |
+
}
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
// Finds the next marker.
|
1179 |
+
int jpeg_decoder::next_marker()
|
1180 |
+
{
|
1181 |
+
uint c, bytes;
|
1182 |
+
|
1183 |
+
bytes = 0;
|
1184 |
+
|
1185 |
+
do
|
1186 |
+
{
|
1187 |
+
do
|
1188 |
+
{
|
1189 |
+
bytes++;
|
1190 |
+
c = get_bits(8);
|
1191 |
+
} while (c != 0xFF);
|
1192 |
+
|
1193 |
+
do
|
1194 |
+
{
|
1195 |
+
c = get_bits(8);
|
1196 |
+
} while (c == 0xFF);
|
1197 |
+
|
1198 |
+
} while (c == 0);
|
1199 |
+
|
1200 |
+
// If bytes > 0 here, there where extra bytes before the marker (not good).
|
1201 |
+
|
1202 |
+
return c;
|
1203 |
+
}
|
1204 |
+
|
1205 |
+
// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
|
1206 |
+
// encountered.
|
1207 |
+
int jpeg_decoder::process_markers()
|
1208 |
+
{
|
1209 |
+
int c;
|
1210 |
+
|
1211 |
+
for ( ; ; )
|
1212 |
+
{
|
1213 |
+
c = next_marker();
|
1214 |
+
|
1215 |
+
switch (c)
|
1216 |
+
{
|
1217 |
+
case M_SOF0:
|
1218 |
+
case M_SOF1:
|
1219 |
+
case M_SOF2:
|
1220 |
+
case M_SOF3:
|
1221 |
+
case M_SOF5:
|
1222 |
+
case M_SOF6:
|
1223 |
+
case M_SOF7:
|
1224 |
+
// case M_JPG:
|
1225 |
+
case M_SOF9:
|
1226 |
+
case M_SOF10:
|
1227 |
+
case M_SOF11:
|
1228 |
+
case M_SOF13:
|
1229 |
+
case M_SOF14:
|
1230 |
+
case M_SOF15:
|
1231 |
+
case M_SOI:
|
1232 |
+
case M_EOI:
|
1233 |
+
case M_SOS:
|
1234 |
+
{
|
1235 |
+
return c;
|
1236 |
+
}
|
1237 |
+
case M_DHT:
|
1238 |
+
{
|
1239 |
+
read_dht_marker();
|
1240 |
+
break;
|
1241 |
+
}
|
1242 |
+
// No arithmitic support - dumb patents!
|
1243 |
+
case M_DAC:
|
1244 |
+
{
|
1245 |
+
stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
|
1246 |
+
break;
|
1247 |
+
}
|
1248 |
+
case M_DQT:
|
1249 |
+
{
|
1250 |
+
read_dqt_marker();
|
1251 |
+
break;
|
1252 |
+
}
|
1253 |
+
case M_DRI:
|
1254 |
+
{
|
1255 |
+
read_dri_marker();
|
1256 |
+
break;
|
1257 |
+
}
|
1258 |
+
//case M_APP0: /* no need to read the JFIF marker */
|
1259 |
+
|
1260 |
+
case M_JPG:
|
1261 |
+
case M_RST0: /* no parameters */
|
1262 |
+
case M_RST1:
|
1263 |
+
case M_RST2:
|
1264 |
+
case M_RST3:
|
1265 |
+
case M_RST4:
|
1266 |
+
case M_RST5:
|
1267 |
+
case M_RST6:
|
1268 |
+
case M_RST7:
|
1269 |
+
case M_TEM:
|
1270 |
+
{
|
1271 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
1272 |
+
break;
|
1273 |
+
}
|
1274 |
+
default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
|
1275 |
+
{
|
1276 |
+
skip_variable_marker();
|
1277 |
+
break;
|
1278 |
+
}
|
1279 |
+
}
|
1280 |
+
}
|
1281 |
+
}
|
1282 |
+
|
1283 |
+
// Finds the start of image (SOI) marker.
|
1284 |
+
// This code is rather defensive: it only checks the first 512 bytes to avoid
|
1285 |
+
// false positives.
|
1286 |
+
void jpeg_decoder::locate_soi_marker()
|
1287 |
+
{
|
1288 |
+
uint lastchar, thischar;
|
1289 |
+
uint bytesleft;
|
1290 |
+
|
1291 |
+
lastchar = get_bits(8);
|
1292 |
+
|
1293 |
+
thischar = get_bits(8);
|
1294 |
+
|
1295 |
+
/* ok if it's a normal JPEG file without a special header */
|
1296 |
+
|
1297 |
+
if ((lastchar == 0xFF) && (thischar == M_SOI))
|
1298 |
+
return;
|
1299 |
+
|
1300 |
+
bytesleft = 4096; //512;
|
1301 |
+
|
1302 |
+
for ( ; ; )
|
1303 |
+
{
|
1304 |
+
if (--bytesleft == 0)
|
1305 |
+
stop_decoding(JPGD_NOT_JPEG);
|
1306 |
+
|
1307 |
+
lastchar = thischar;
|
1308 |
+
|
1309 |
+
thischar = get_bits(8);
|
1310 |
+
|
1311 |
+
if (lastchar == 0xFF)
|
1312 |
+
{
|
1313 |
+
if (thischar == M_SOI)
|
1314 |
+
break;
|
1315 |
+
else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end
|
1316 |
+
stop_decoding(JPGD_NOT_JPEG);
|
1317 |
+
}
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
// Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
|
1321 |
+
thischar = (m_bit_buf >> 24) & 0xFF;
|
1322 |
+
|
1323 |
+
if (thischar != 0xFF)
|
1324 |
+
stop_decoding(JPGD_NOT_JPEG);
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
// Find a start of frame (SOF) marker.
|
1328 |
+
void jpeg_decoder::locate_sof_marker()
|
1329 |
+
{
|
1330 |
+
locate_soi_marker();
|
1331 |
+
|
1332 |
+
int c = process_markers();
|
1333 |
+
|
1334 |
+
switch (c)
|
1335 |
+
{
|
1336 |
+
case M_SOF2:
|
1337 |
+
m_progressive_flag = JPGD_TRUE;
|
1338 |
+
case M_SOF0: /* baseline DCT */
|
1339 |
+
case M_SOF1: /* extended sequential DCT */
|
1340 |
+
{
|
1341 |
+
read_sof_marker();
|
1342 |
+
break;
|
1343 |
+
}
|
1344 |
+
case M_SOF9: /* Arithmitic coding */
|
1345 |
+
{
|
1346 |
+
stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
|
1347 |
+
break;
|
1348 |
+
}
|
1349 |
+
default:
|
1350 |
+
{
|
1351 |
+
stop_decoding(JPGD_UNSUPPORTED_MARKER);
|
1352 |
+
break;
|
1353 |
+
}
|
1354 |
+
}
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
// Find a start of scan (SOS) marker.
|
1358 |
+
int jpeg_decoder::locate_sos_marker()
|
1359 |
+
{
|
1360 |
+
int c;
|
1361 |
+
|
1362 |
+
c = process_markers();
|
1363 |
+
|
1364 |
+
if (c == M_EOI)
|
1365 |
+
return JPGD_FALSE;
|
1366 |
+
else if (c != M_SOS)
|
1367 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
1368 |
+
|
1369 |
+
read_sos_marker();
|
1370 |
+
|
1371 |
+
return JPGD_TRUE;
|
1372 |
+
}
|
1373 |
+
|
1374 |
+
// Reset everything to default/uninitialized state.
|
1375 |
+
void jpeg_decoder::init(jpeg_decoder_stream *pStream)
|
1376 |
+
{
|
1377 |
+
m_pMem_blocks = NULL;
|
1378 |
+
m_error_code = JPGD_SUCCESS;
|
1379 |
+
m_ready_flag = false;
|
1380 |
+
m_image_x_size = m_image_y_size = 0;
|
1381 |
+
m_pStream = pStream;
|
1382 |
+
m_progressive_flag = JPGD_FALSE;
|
1383 |
+
|
1384 |
+
memset(m_huff_ac, 0, sizeof(m_huff_ac));
|
1385 |
+
memset(m_huff_num, 0, sizeof(m_huff_num));
|
1386 |
+
memset(m_huff_val, 0, sizeof(m_huff_val));
|
1387 |
+
memset(m_quant, 0, sizeof(m_quant));
|
1388 |
+
|
1389 |
+
m_scan_type = 0;
|
1390 |
+
m_comps_in_frame = 0;
|
1391 |
+
|
1392 |
+
memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp));
|
1393 |
+
memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp));
|
1394 |
+
memset(m_comp_quant, 0, sizeof(m_comp_quant));
|
1395 |
+
memset(m_comp_ident, 0, sizeof(m_comp_ident));
|
1396 |
+
memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks));
|
1397 |
+
memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks));
|
1398 |
+
|
1399 |
+
m_comps_in_scan = 0;
|
1400 |
+
memset(m_comp_list, 0, sizeof(m_comp_list));
|
1401 |
+
memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab));
|
1402 |
+
memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab));
|
1403 |
+
|
1404 |
+
m_spectral_start = 0;
|
1405 |
+
m_spectral_end = 0;
|
1406 |
+
m_successive_low = 0;
|
1407 |
+
m_successive_high = 0;
|
1408 |
+
m_max_mcu_x_size = 0;
|
1409 |
+
m_max_mcu_y_size = 0;
|
1410 |
+
m_blocks_per_mcu = 0;
|
1411 |
+
m_max_blocks_per_row = 0;
|
1412 |
+
m_mcus_per_row = 0;
|
1413 |
+
m_mcus_per_col = 0;
|
1414 |
+
m_expanded_blocks_per_component = 0;
|
1415 |
+
m_expanded_blocks_per_mcu = 0;
|
1416 |
+
m_expanded_blocks_per_row = 0;
|
1417 |
+
m_freq_domain_chroma_upsample = false;
|
1418 |
+
|
1419 |
+
memset(m_mcu_org, 0, sizeof(m_mcu_org));
|
1420 |
+
|
1421 |
+
m_total_lines_left = 0;
|
1422 |
+
m_mcu_lines_left = 0;
|
1423 |
+
m_real_dest_bytes_per_scan_line = 0;
|
1424 |
+
m_dest_bytes_per_scan_line = 0;
|
1425 |
+
m_dest_bytes_per_pixel = 0;
|
1426 |
+
|
1427 |
+
memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs));
|
1428 |
+
|
1429 |
+
memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs));
|
1430 |
+
memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs));
|
1431 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
1432 |
+
|
1433 |
+
m_eob_run = 0;
|
1434 |
+
|
1435 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
1436 |
+
|
1437 |
+
m_pIn_buf_ofs = m_in_buf;
|
1438 |
+
m_in_buf_left = 0;
|
1439 |
+
m_eof_flag = false;
|
1440 |
+
m_tem_flag = 0;
|
1441 |
+
|
1442 |
+
memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start));
|
1443 |
+
memset(m_in_buf, 0, sizeof(m_in_buf));
|
1444 |
+
memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end));
|
1445 |
+
|
1446 |
+
m_restart_interval = 0;
|
1447 |
+
m_restarts_left = 0;
|
1448 |
+
m_next_restart_num = 0;
|
1449 |
+
|
1450 |
+
m_max_mcus_per_row = 0;
|
1451 |
+
m_max_blocks_per_mcu = 0;
|
1452 |
+
m_max_mcus_per_col = 0;
|
1453 |
+
|
1454 |
+
memset(m_last_dc_val, 0, sizeof(m_last_dc_val));
|
1455 |
+
m_pMCU_coefficients = NULL;
|
1456 |
+
m_pSample_buf = NULL;
|
1457 |
+
|
1458 |
+
m_total_bytes_read = 0;
|
1459 |
+
|
1460 |
+
m_pScan_line_0 = NULL;
|
1461 |
+
m_pScan_line_1 = NULL;
|
1462 |
+
|
1463 |
+
// Ready the input buffer.
|
1464 |
+
prep_in_buffer();
|
1465 |
+
|
1466 |
+
// Prime the bit buffer.
|
1467 |
+
m_bits_left = 16;
|
1468 |
+
m_bit_buf = 0;
|
1469 |
+
|
1470 |
+
get_bits(16);
|
1471 |
+
get_bits(16);
|
1472 |
+
|
1473 |
+
for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++)
|
1474 |
+
m_mcu_block_max_zag[i] = 64;
|
1475 |
+
}
|
1476 |
+
|
1477 |
+
#define SCALEBITS 16
|
1478 |
+
#define ONE_HALF ((int) 1 << (SCALEBITS-1))
|
1479 |
+
#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f))
|
1480 |
+
|
1481 |
+
// Create a few tables that allow us to quickly convert YCbCr to RGB.
|
1482 |
+
void jpeg_decoder::create_look_ups()
|
1483 |
+
{
|
1484 |
+
for (int i = 0; i <= 255; i++)
|
1485 |
+
{
|
1486 |
+
int k = i - 128;
|
1487 |
+
m_crr[i] = ( FIX(1.40200f) * k + ONE_HALF) >> SCALEBITS;
|
1488 |
+
m_cbb[i] = ( FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS;
|
1489 |
+
m_crg[i] = (-FIX(0.71414f)) * k;
|
1490 |
+
m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF;
|
1491 |
+
}
|
1492 |
+
}
|
1493 |
+
|
1494 |
+
// This method throws back into the stream any bytes that where read
|
1495 |
+
// into the bit buffer during initial marker scanning.
|
1496 |
+
void jpeg_decoder::fix_in_buffer()
|
1497 |
+
{
|
1498 |
+
// In case any 0xFF's where pulled into the buffer during marker scanning.
|
1499 |
+
JPGD_ASSERT((m_bits_left & 7) == 0);
|
1500 |
+
|
1501 |
+
if (m_bits_left == 16)
|
1502 |
+
stuff_char( (uint8)(m_bit_buf & 0xFF));
|
1503 |
+
|
1504 |
+
if (m_bits_left >= 8)
|
1505 |
+
stuff_char( (uint8)((m_bit_buf >> 8) & 0xFF));
|
1506 |
+
|
1507 |
+
stuff_char((uint8)((m_bit_buf >> 16) & 0xFF));
|
1508 |
+
stuff_char((uint8)((m_bit_buf >> 24) & 0xFF));
|
1509 |
+
|
1510 |
+
m_bits_left = 16;
|
1511 |
+
get_bits_no_markers(16);
|
1512 |
+
get_bits_no_markers(16);
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
void jpeg_decoder::transform_mcu(int mcu_row)
|
1516 |
+
{
|
1517 |
+
jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
|
1518 |
+
uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64;
|
1519 |
+
|
1520 |
+
for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
1521 |
+
{
|
1522 |
+
idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
|
1523 |
+
pSrc_ptr += 64;
|
1524 |
+
pDst_ptr += 64;
|
1525 |
+
}
|
1526 |
+
}
|
1527 |
+
|
1528 |
+
static const uint8 s_max_rc[64] =
|
1529 |
+
{
|
1530 |
+
17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86,
|
1531 |
+
102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136,
|
1532 |
+
136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
|
1533 |
+
136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136
|
1534 |
+
};
|
1535 |
+
|
1536 |
+
void jpeg_decoder::transform_mcu_expand(int mcu_row)
|
1537 |
+
{
|
1538 |
+
jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
|
1539 |
+
uint8* pDst_ptr = m_pSample_buf + mcu_row * m_expanded_blocks_per_mcu * 64;
|
1540 |
+
|
1541 |
+
// Y IDCT
|
1542 |
+
int mcu_block;
|
1543 |
+
for (mcu_block = 0; mcu_block < m_expanded_blocks_per_component; mcu_block++)
|
1544 |
+
{
|
1545 |
+
idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
|
1546 |
+
pSrc_ptr += 64;
|
1547 |
+
pDst_ptr += 64;
|
1548 |
+
}
|
1549 |
+
|
1550 |
+
// Chroma IDCT, with upsampling
|
1551 |
+
jpgd_block_t temp_block[64];
|
1552 |
+
|
1553 |
+
for (int i = 0; i < 2; i++)
|
1554 |
+
{
|
1555 |
+
DCT_Upsample::Matrix44 P, Q, R, S;
|
1556 |
+
|
1557 |
+
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1);
|
1558 |
+
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64);
|
1559 |
+
|
1560 |
+
switch (s_max_rc[m_mcu_block_max_zag[mcu_block++] - 1])
|
1561 |
+
{
|
1562 |
+
case 1*16+1:
|
1563 |
+
DCT_Upsample::P_Q<1, 1>::calc(P, Q, pSrc_ptr);
|
1564 |
+
DCT_Upsample::R_S<1, 1>::calc(R, S, pSrc_ptr);
|
1565 |
+
break;
|
1566 |
+
case 1*16+2:
|
1567 |
+
DCT_Upsample::P_Q<1, 2>::calc(P, Q, pSrc_ptr);
|
1568 |
+
DCT_Upsample::R_S<1, 2>::calc(R, S, pSrc_ptr);
|
1569 |
+
break;
|
1570 |
+
case 2*16+2:
|
1571 |
+
DCT_Upsample::P_Q<2, 2>::calc(P, Q, pSrc_ptr);
|
1572 |
+
DCT_Upsample::R_S<2, 2>::calc(R, S, pSrc_ptr);
|
1573 |
+
break;
|
1574 |
+
case 3*16+2:
|
1575 |
+
DCT_Upsample::P_Q<3, 2>::calc(P, Q, pSrc_ptr);
|
1576 |
+
DCT_Upsample::R_S<3, 2>::calc(R, S, pSrc_ptr);
|
1577 |
+
break;
|
1578 |
+
case 3*16+3:
|
1579 |
+
DCT_Upsample::P_Q<3, 3>::calc(P, Q, pSrc_ptr);
|
1580 |
+
DCT_Upsample::R_S<3, 3>::calc(R, S, pSrc_ptr);
|
1581 |
+
break;
|
1582 |
+
case 3*16+4:
|
1583 |
+
DCT_Upsample::P_Q<3, 4>::calc(P, Q, pSrc_ptr);
|
1584 |
+
DCT_Upsample::R_S<3, 4>::calc(R, S, pSrc_ptr);
|
1585 |
+
break;
|
1586 |
+
case 4*16+4:
|
1587 |
+
DCT_Upsample::P_Q<4, 4>::calc(P, Q, pSrc_ptr);
|
1588 |
+
DCT_Upsample::R_S<4, 4>::calc(R, S, pSrc_ptr);
|
1589 |
+
break;
|
1590 |
+
case 5*16+4:
|
1591 |
+
DCT_Upsample::P_Q<5, 4>::calc(P, Q, pSrc_ptr);
|
1592 |
+
DCT_Upsample::R_S<5, 4>::calc(R, S, pSrc_ptr);
|
1593 |
+
break;
|
1594 |
+
case 5*16+5:
|
1595 |
+
DCT_Upsample::P_Q<5, 5>::calc(P, Q, pSrc_ptr);
|
1596 |
+
DCT_Upsample::R_S<5, 5>::calc(R, S, pSrc_ptr);
|
1597 |
+
break;
|
1598 |
+
case 5*16+6:
|
1599 |
+
DCT_Upsample::P_Q<5, 6>::calc(P, Q, pSrc_ptr);
|
1600 |
+
DCT_Upsample::R_S<5, 6>::calc(R, S, pSrc_ptr);
|
1601 |
+
break;
|
1602 |
+
case 6*16+6:
|
1603 |
+
DCT_Upsample::P_Q<6, 6>::calc(P, Q, pSrc_ptr);
|
1604 |
+
DCT_Upsample::R_S<6, 6>::calc(R, S, pSrc_ptr);
|
1605 |
+
break;
|
1606 |
+
case 7*16+6:
|
1607 |
+
DCT_Upsample::P_Q<7, 6>::calc(P, Q, pSrc_ptr);
|
1608 |
+
DCT_Upsample::R_S<7, 6>::calc(R, S, pSrc_ptr);
|
1609 |
+
break;
|
1610 |
+
case 7*16+7:
|
1611 |
+
DCT_Upsample::P_Q<7, 7>::calc(P, Q, pSrc_ptr);
|
1612 |
+
DCT_Upsample::R_S<7, 7>::calc(R, S, pSrc_ptr);
|
1613 |
+
break;
|
1614 |
+
case 7*16+8:
|
1615 |
+
DCT_Upsample::P_Q<7, 8>::calc(P, Q, pSrc_ptr);
|
1616 |
+
DCT_Upsample::R_S<7, 8>::calc(R, S, pSrc_ptr);
|
1617 |
+
break;
|
1618 |
+
case 8*16+8:
|
1619 |
+
DCT_Upsample::P_Q<8, 8>::calc(P, Q, pSrc_ptr);
|
1620 |
+
DCT_Upsample::R_S<8, 8>::calc(R, S, pSrc_ptr);
|
1621 |
+
break;
|
1622 |
+
default:
|
1623 |
+
JPGD_ASSERT(false);
|
1624 |
+
}
|
1625 |
+
|
1626 |
+
DCT_Upsample::Matrix44 a(P + Q); P -= Q;
|
1627 |
+
DCT_Upsample::Matrix44& b = P;
|
1628 |
+
DCT_Upsample::Matrix44 c(R + S); R -= S;
|
1629 |
+
DCT_Upsample::Matrix44& d = R;
|
1630 |
+
|
1631 |
+
DCT_Upsample::Matrix44::add_and_store(temp_block, a, c);
|
1632 |
+
idct_4x4(temp_block, pDst_ptr);
|
1633 |
+
pDst_ptr += 64;
|
1634 |
+
|
1635 |
+
DCT_Upsample::Matrix44::sub_and_store(temp_block, a, c);
|
1636 |
+
idct_4x4(temp_block, pDst_ptr);
|
1637 |
+
pDst_ptr += 64;
|
1638 |
+
|
1639 |
+
DCT_Upsample::Matrix44::add_and_store(temp_block, b, d);
|
1640 |
+
idct_4x4(temp_block, pDst_ptr);
|
1641 |
+
pDst_ptr += 64;
|
1642 |
+
|
1643 |
+
DCT_Upsample::Matrix44::sub_and_store(temp_block, b, d);
|
1644 |
+
idct_4x4(temp_block, pDst_ptr);
|
1645 |
+
pDst_ptr += 64;
|
1646 |
+
|
1647 |
+
pSrc_ptr += 64;
|
1648 |
+
}
|
1649 |
+
}
|
1650 |
+
|
1651 |
+
// Loads and dequantizes the next row of (already decoded) coefficients.
|
1652 |
+
// Progressive images only.
|
1653 |
+
void jpeg_decoder::load_next_row()
|
1654 |
+
{
|
1655 |
+
int i;
|
1656 |
+
jpgd_block_t *p;
|
1657 |
+
jpgd_quant_t *q;
|
1658 |
+
int mcu_row, mcu_block, row_block = 0;
|
1659 |
+
int component_num, component_id;
|
1660 |
+
int block_x_mcu[JPGD_MAX_COMPONENTS];
|
1661 |
+
|
1662 |
+
memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int));
|
1663 |
+
|
1664 |
+
for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
1665 |
+
{
|
1666 |
+
int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
|
1667 |
+
|
1668 |
+
for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
1669 |
+
{
|
1670 |
+
component_id = m_mcu_org[mcu_block];
|
1671 |
+
q = m_quant[m_comp_quant[component_id]];
|
1672 |
+
|
1673 |
+
p = m_pMCU_coefficients + 64 * mcu_block;
|
1674 |
+
|
1675 |
+
jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
1676 |
+
jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
1677 |
+
p[0] = pDC[0];
|
1678 |
+
memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t));
|
1679 |
+
|
1680 |
+
for (i = 63; i > 0; i--)
|
1681 |
+
if (p[g_ZAG[i]])
|
1682 |
+
break;
|
1683 |
+
|
1684 |
+
m_mcu_block_max_zag[mcu_block] = i + 1;
|
1685 |
+
|
1686 |
+
for ( ; i >= 0; i--)
|
1687 |
+
if (p[g_ZAG[i]])
|
1688 |
+
p[g_ZAG[i]] = static_cast<jpgd_block_t>(p[g_ZAG[i]] * q[i]);
|
1689 |
+
|
1690 |
+
row_block++;
|
1691 |
+
|
1692 |
+
if (m_comps_in_scan == 1)
|
1693 |
+
block_x_mcu[component_id]++;
|
1694 |
+
else
|
1695 |
+
{
|
1696 |
+
if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
|
1697 |
+
{
|
1698 |
+
block_x_mcu_ofs = 0;
|
1699 |
+
|
1700 |
+
if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
|
1701 |
+
{
|
1702 |
+
block_y_mcu_ofs = 0;
|
1703 |
+
|
1704 |
+
block_x_mcu[component_id] += m_comp_h_samp[component_id];
|
1705 |
+
}
|
1706 |
+
}
|
1707 |
+
}
|
1708 |
+
}
|
1709 |
+
|
1710 |
+
if (m_freq_domain_chroma_upsample)
|
1711 |
+
transform_mcu_expand(mcu_row);
|
1712 |
+
else
|
1713 |
+
transform_mcu(mcu_row);
|
1714 |
+
}
|
1715 |
+
|
1716 |
+
if (m_comps_in_scan == 1)
|
1717 |
+
m_block_y_mcu[m_comp_list[0]]++;
|
1718 |
+
else
|
1719 |
+
{
|
1720 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
1721 |
+
{
|
1722 |
+
component_id = m_comp_list[component_num];
|
1723 |
+
|
1724 |
+
m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
|
1725 |
+
}
|
1726 |
+
}
|
1727 |
+
}
|
1728 |
+
|
1729 |
+
// Restart interval processing.
|
1730 |
+
void jpeg_decoder::process_restart()
|
1731 |
+
{
|
1732 |
+
int i;
|
1733 |
+
int c = 0;
|
1734 |
+
|
1735 |
+
// Align to a byte boundry
|
1736 |
+
// FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
|
1737 |
+
//get_bits_no_markers(m_bits_left & 7);
|
1738 |
+
|
1739 |
+
// Let's scan a little bit to find the marker, but not _too_ far.
|
1740 |
+
// 1536 is a "fudge factor" that determines how much to scan.
|
1741 |
+
for (i = 1536; i > 0; i--)
|
1742 |
+
if (get_char() == 0xFF)
|
1743 |
+
break;
|
1744 |
+
|
1745 |
+
if (i == 0)
|
1746 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
1747 |
+
|
1748 |
+
for ( ; i > 0; i--)
|
1749 |
+
if ((c = get_char()) != 0xFF)
|
1750 |
+
break;
|
1751 |
+
|
1752 |
+
if (i == 0)
|
1753 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
1754 |
+
|
1755 |
+
// Is it the expected marker? If not, something bad happened.
|
1756 |
+
if (c != (m_next_restart_num + M_RST0))
|
1757 |
+
stop_decoding(JPGD_BAD_RESTART_MARKER);
|
1758 |
+
|
1759 |
+
// Reset each component's DC prediction values.
|
1760 |
+
memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
|
1761 |
+
|
1762 |
+
m_eob_run = 0;
|
1763 |
+
|
1764 |
+
m_restarts_left = m_restart_interval;
|
1765 |
+
|
1766 |
+
m_next_restart_num = (m_next_restart_num + 1) & 7;
|
1767 |
+
|
1768 |
+
// Get the bit buffer going again...
|
1769 |
+
|
1770 |
+
m_bits_left = 16;
|
1771 |
+
get_bits_no_markers(16);
|
1772 |
+
get_bits_no_markers(16);
|
1773 |
+
}
|
1774 |
+
|
1775 |
+
static inline int dequantize_ac(int c, int q) { c *= q; return c; }
|
1776 |
+
|
1777 |
+
// Decodes and dequantizes the next row of coefficients.
|
1778 |
+
void jpeg_decoder::decode_next_row()
|
1779 |
+
{
|
1780 |
+
int row_block = 0;
|
1781 |
+
|
1782 |
+
for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
1783 |
+
{
|
1784 |
+
if ((m_restart_interval) && (m_restarts_left == 0))
|
1785 |
+
process_restart();
|
1786 |
+
|
1787 |
+
jpgd_block_t* p = m_pMCU_coefficients;
|
1788 |
+
for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64)
|
1789 |
+
{
|
1790 |
+
int component_id = m_mcu_org[mcu_block];
|
1791 |
+
jpgd_quant_t* q = m_quant[m_comp_quant[component_id]];
|
1792 |
+
|
1793 |
+
int r, s;
|
1794 |
+
s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r);
|
1795 |
+
s = HUFF_EXTEND(r, s);
|
1796 |
+
|
1797 |
+
m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]);
|
1798 |
+
|
1799 |
+
p[0] = static_cast<jpgd_block_t>(s * q[0]);
|
1800 |
+
|
1801 |
+
int prev_num_set = m_mcu_block_max_zag[mcu_block];
|
1802 |
+
|
1803 |
+
huff_tables *pH = m_pHuff_tabs[m_comp_ac_tab[component_id]];
|
1804 |
+
|
1805 |
+
int k;
|
1806 |
+
for (k = 1; k < 64; k++)
|
1807 |
+
{
|
1808 |
+
int extra_bits;
|
1809 |
+
s = huff_decode(pH, extra_bits);
|
1810 |
+
|
1811 |
+
r = s >> 4;
|
1812 |
+
s &= 15;
|
1813 |
+
|
1814 |
+
if (s)
|
1815 |
+
{
|
1816 |
+
if (r)
|
1817 |
+
{
|
1818 |
+
if ((k + r) > 63)
|
1819 |
+
stop_decoding(JPGD_DECODE_ERROR);
|
1820 |
+
|
1821 |
+
if (k < prev_num_set)
|
1822 |
+
{
|
1823 |
+
int n = JPGD_MIN(r, prev_num_set - k);
|
1824 |
+
int kt = k;
|
1825 |
+
while (n--)
|
1826 |
+
p[g_ZAG[kt++]] = 0;
|
1827 |
+
}
|
1828 |
+
|
1829 |
+
k += r;
|
1830 |
+
}
|
1831 |
+
|
1832 |
+
s = HUFF_EXTEND(extra_bits, s);
|
1833 |
+
|
1834 |
+
JPGD_ASSERT(k < 64);
|
1835 |
+
|
1836 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k];
|
1837 |
+
}
|
1838 |
+
else
|
1839 |
+
{
|
1840 |
+
if (r == 15)
|
1841 |
+
{
|
1842 |
+
if ((k + 16) > 64)
|
1843 |
+
stop_decoding(JPGD_DECODE_ERROR);
|
1844 |
+
|
1845 |
+
if (k < prev_num_set)
|
1846 |
+
{
|
1847 |
+
int n = JPGD_MIN(16, prev_num_set - k);
|
1848 |
+
int kt = k;
|
1849 |
+
while (n--)
|
1850 |
+
{
|
1851 |
+
JPGD_ASSERT(kt <= 63);
|
1852 |
+
p[g_ZAG[kt++]] = 0;
|
1853 |
+
}
|
1854 |
+
}
|
1855 |
+
|
1856 |
+
k += 16 - 1; // - 1 because the loop counter is k
|
1857 |
+
// BEGIN EPIC MOD
|
1858 |
+
JPGD_ASSERT(k < 64 && p[g_ZAG[k]] == 0);
|
1859 |
+
// END EPIC MOD
|
1860 |
+
}
|
1861 |
+
else
|
1862 |
+
break;
|
1863 |
+
}
|
1864 |
+
}
|
1865 |
+
|
1866 |
+
if (k < prev_num_set)
|
1867 |
+
{
|
1868 |
+
int kt = k;
|
1869 |
+
while (kt < prev_num_set)
|
1870 |
+
p[g_ZAG[kt++]] = 0;
|
1871 |
+
}
|
1872 |
+
|
1873 |
+
m_mcu_block_max_zag[mcu_block] = k;
|
1874 |
+
|
1875 |
+
row_block++;
|
1876 |
+
}
|
1877 |
+
|
1878 |
+
if (m_freq_domain_chroma_upsample)
|
1879 |
+
transform_mcu_expand(mcu_row);
|
1880 |
+
else
|
1881 |
+
transform_mcu(mcu_row);
|
1882 |
+
|
1883 |
+
m_restarts_left--;
|
1884 |
+
}
|
1885 |
+
}
|
1886 |
+
|
1887 |
+
// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
|
1888 |
+
void jpeg_decoder::H1V1Convert()
|
1889 |
+
{
|
1890 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
1891 |
+
uint8 *d = m_pScan_line_0;
|
1892 |
+
uint8 *s = m_pSample_buf + row * 8;
|
1893 |
+
|
1894 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
1895 |
+
{
|
1896 |
+
for (int j = 0; j < 8; j++)
|
1897 |
+
{
|
1898 |
+
int y = s[j];
|
1899 |
+
int cb = s[64+j];
|
1900 |
+
int cr = s[128+j];
|
1901 |
+
|
1902 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
1903 |
+
{
|
1904 |
+
d[0] = clamp(y + m_cbb[cb]);
|
1905 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
1906 |
+
d[2] = clamp(y + m_crr[cr]);
|
1907 |
+
d[3] = 255;
|
1908 |
+
}
|
1909 |
+
else
|
1910 |
+
{
|
1911 |
+
d[0] = clamp(y + m_crr[cr]);
|
1912 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
1913 |
+
d[2] = clamp(y + m_cbb[cb]);
|
1914 |
+
d[3] = 255;
|
1915 |
+
}
|
1916 |
+
d += 4;
|
1917 |
+
}
|
1918 |
+
|
1919 |
+
s += 64*3;
|
1920 |
+
}
|
1921 |
+
}
|
1922 |
+
|
1923 |
+
// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
|
1924 |
+
void jpeg_decoder::H2V1Convert()
|
1925 |
+
{
|
1926 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
1927 |
+
uint8 *d0 = m_pScan_line_0;
|
1928 |
+
uint8 *y = m_pSample_buf + row * 8;
|
1929 |
+
uint8 *c = m_pSample_buf + 2*64 + row * 8;
|
1930 |
+
|
1931 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
1932 |
+
{
|
1933 |
+
for (int l = 0; l < 2; l++)
|
1934 |
+
{
|
1935 |
+
for (int j = 0; j < 4; j++)
|
1936 |
+
{
|
1937 |
+
int cb = c[0];
|
1938 |
+
int cr = c[64];
|
1939 |
+
|
1940 |
+
int rc = m_crr[cr];
|
1941 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
1942 |
+
int bc = m_cbb[cb];
|
1943 |
+
|
1944 |
+
int yy = y[j<<1];
|
1945 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
1946 |
+
{
|
1947 |
+
d0[0] = clamp(yy+bc);
|
1948 |
+
d0[1] = clamp(yy+gc);
|
1949 |
+
d0[2] = clamp(yy+rc);
|
1950 |
+
d0[3] = 255;
|
1951 |
+
yy = y[(j<<1)+1];
|
1952 |
+
d0[4] = clamp(yy+bc);
|
1953 |
+
d0[5] = clamp(yy+gc);
|
1954 |
+
d0[6] = clamp(yy+rc);
|
1955 |
+
d0[7] = 255;
|
1956 |
+
}
|
1957 |
+
else
|
1958 |
+
{
|
1959 |
+
d0[0] = clamp(yy+rc);
|
1960 |
+
d0[1] = clamp(yy+gc);
|
1961 |
+
d0[2] = clamp(yy+bc);
|
1962 |
+
d0[3] = 255;
|
1963 |
+
yy = y[(j<<1)+1];
|
1964 |
+
d0[4] = clamp(yy+rc);
|
1965 |
+
d0[5] = clamp(yy+gc);
|
1966 |
+
d0[6] = clamp(yy+bc);
|
1967 |
+
d0[7] = 255;
|
1968 |
+
}
|
1969 |
+
|
1970 |
+
d0 += 8;
|
1971 |
+
|
1972 |
+
c++;
|
1973 |
+
}
|
1974 |
+
y += 64;
|
1975 |
+
}
|
1976 |
+
|
1977 |
+
y += 64*4 - 64*2;
|
1978 |
+
c += 64*4 - 8;
|
1979 |
+
}
|
1980 |
+
}
|
1981 |
+
|
1982 |
+
// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
|
1983 |
+
void jpeg_decoder::H1V2Convert()
|
1984 |
+
{
|
1985 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
1986 |
+
uint8 *d0 = m_pScan_line_0;
|
1987 |
+
uint8 *d1 = m_pScan_line_1;
|
1988 |
+
uint8 *y;
|
1989 |
+
uint8 *c;
|
1990 |
+
|
1991 |
+
if (row < 8)
|
1992 |
+
y = m_pSample_buf + row * 8;
|
1993 |
+
else
|
1994 |
+
y = m_pSample_buf + 64*1 + (row & 7) * 8;
|
1995 |
+
|
1996 |
+
c = m_pSample_buf + 64*2 + (row >> 1) * 8;
|
1997 |
+
|
1998 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
1999 |
+
{
|
2000 |
+
for (int j = 0; j < 8; j++)
|
2001 |
+
{
|
2002 |
+
int cb = c[0+j];
|
2003 |
+
int cr = c[64+j];
|
2004 |
+
|
2005 |
+
int rc = m_crr[cr];
|
2006 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
2007 |
+
int bc = m_cbb[cb];
|
2008 |
+
|
2009 |
+
int yy = y[j];
|
2010 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
2011 |
+
{
|
2012 |
+
d0[0] = clamp(yy+bc);
|
2013 |
+
d0[1] = clamp(yy+gc);
|
2014 |
+
d0[2] = clamp(yy+rc);
|
2015 |
+
d0[3] = 255;
|
2016 |
+
yy = y[8+j];
|
2017 |
+
d1[0] = clamp(yy+bc);
|
2018 |
+
d1[1] = clamp(yy+gc);
|
2019 |
+
d1[2] = clamp(yy+rc);
|
2020 |
+
d1[3] = 255;
|
2021 |
+
}
|
2022 |
+
else
|
2023 |
+
{
|
2024 |
+
d0[0] = clamp(yy+rc);
|
2025 |
+
d0[1] = clamp(yy+gc);
|
2026 |
+
d0[2] = clamp(yy+bc);
|
2027 |
+
d0[3] = 255;
|
2028 |
+
yy = y[8+j];
|
2029 |
+
d1[0] = clamp(yy+rc);
|
2030 |
+
d1[1] = clamp(yy+gc);
|
2031 |
+
d1[2] = clamp(yy+bc);
|
2032 |
+
d1[3] = 255;
|
2033 |
+
}
|
2034 |
+
|
2035 |
+
d0 += 4;
|
2036 |
+
d1 += 4;
|
2037 |
+
}
|
2038 |
+
|
2039 |
+
y += 64*4;
|
2040 |
+
c += 64*4;
|
2041 |
+
}
|
2042 |
+
}
|
2043 |
+
|
2044 |
+
// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
|
2045 |
+
void jpeg_decoder::H2V2Convert()
|
2046 |
+
{
|
2047 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
2048 |
+
uint8 *d0 = m_pScan_line_0;
|
2049 |
+
uint8 *d1 = m_pScan_line_1;
|
2050 |
+
uint8 *y;
|
2051 |
+
uint8 *c;
|
2052 |
+
|
2053 |
+
if (row < 8)
|
2054 |
+
y = m_pSample_buf + row * 8;
|
2055 |
+
else
|
2056 |
+
y = m_pSample_buf + 64*2 + (row & 7) * 8;
|
2057 |
+
|
2058 |
+
c = m_pSample_buf + 64*4 + (row >> 1) * 8;
|
2059 |
+
|
2060 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
2061 |
+
{
|
2062 |
+
for (int l = 0; l < 2; l++)
|
2063 |
+
{
|
2064 |
+
for (int j = 0; j < 8; j += 2)
|
2065 |
+
{
|
2066 |
+
int cb = c[0];
|
2067 |
+
int cr = c[64];
|
2068 |
+
|
2069 |
+
int rc = m_crr[cr];
|
2070 |
+
int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
|
2071 |
+
int bc = m_cbb[cb];
|
2072 |
+
|
2073 |
+
int yy = y[j];
|
2074 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
2075 |
+
{
|
2076 |
+
d0[0] = clamp(yy+bc);
|
2077 |
+
d0[1] = clamp(yy+gc);
|
2078 |
+
d0[2] = clamp(yy+rc);
|
2079 |
+
d0[3] = 255;
|
2080 |
+
yy = y[j+1];
|
2081 |
+
d0[4] = clamp(yy+bc);
|
2082 |
+
d0[5] = clamp(yy+gc);
|
2083 |
+
d0[6] = clamp(yy+rc);
|
2084 |
+
d0[7] = 255;
|
2085 |
+
yy = y[j+8];
|
2086 |
+
d1[0] = clamp(yy+bc);
|
2087 |
+
d1[1] = clamp(yy+gc);
|
2088 |
+
d1[2] = clamp(yy+rc);
|
2089 |
+
d1[3] = 255;
|
2090 |
+
yy = y[j+8+1];
|
2091 |
+
d1[4] = clamp(yy+bc);
|
2092 |
+
d1[5] = clamp(yy+gc);
|
2093 |
+
d1[6] = clamp(yy+rc);
|
2094 |
+
d1[7] = 255;
|
2095 |
+
}
|
2096 |
+
else
|
2097 |
+
{
|
2098 |
+
d0[0] = clamp(yy+rc);
|
2099 |
+
d0[1] = clamp(yy+gc);
|
2100 |
+
d0[2] = clamp(yy+bc);
|
2101 |
+
d0[3] = 255;
|
2102 |
+
yy = y[j+1];
|
2103 |
+
d0[4] = clamp(yy+rc);
|
2104 |
+
d0[5] = clamp(yy+gc);
|
2105 |
+
d0[6] = clamp(yy+bc);
|
2106 |
+
d0[7] = 255;
|
2107 |
+
yy = y[j+8];
|
2108 |
+
d1[0] = clamp(yy+rc);
|
2109 |
+
d1[1] = clamp(yy+gc);
|
2110 |
+
d1[2] = clamp(yy+bc);
|
2111 |
+
d1[3] = 255;
|
2112 |
+
yy = y[j+8+1];
|
2113 |
+
d1[4] = clamp(yy+rc);
|
2114 |
+
d1[5] = clamp(yy+gc);
|
2115 |
+
d1[6] = clamp(yy+bc);
|
2116 |
+
d1[7] = 255;
|
2117 |
+
}
|
2118 |
+
|
2119 |
+
d0 += 8;
|
2120 |
+
d1 += 8;
|
2121 |
+
|
2122 |
+
c++;
|
2123 |
+
}
|
2124 |
+
y += 64;
|
2125 |
+
}
|
2126 |
+
|
2127 |
+
y += 64*6 - 64*2;
|
2128 |
+
c += 64*6 - 8;
|
2129 |
+
}
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
// Y (1 block per MCU) to 8-bit grayscale
|
2133 |
+
void jpeg_decoder::gray_convert()
|
2134 |
+
{
|
2135 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
2136 |
+
uint8 *d = m_pScan_line_0;
|
2137 |
+
uint8 *s = m_pSample_buf + row * 8;
|
2138 |
+
|
2139 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
2140 |
+
{
|
2141 |
+
*(uint *)d = *(uint *)s;
|
2142 |
+
*(uint *)(&d[4]) = *(uint *)(&s[4]);
|
2143 |
+
|
2144 |
+
s += 64;
|
2145 |
+
d += 8;
|
2146 |
+
}
|
2147 |
+
}
|
2148 |
+
|
2149 |
+
void jpeg_decoder::expanded_convert()
|
2150 |
+
{
|
2151 |
+
int row = m_max_mcu_y_size - m_mcu_lines_left;
|
2152 |
+
|
2153 |
+
uint8* Py = m_pSample_buf + (row / 8) * 64 * m_comp_h_samp[0] + (row & 7) * 8;
|
2154 |
+
|
2155 |
+
uint8* d = m_pScan_line_0;
|
2156 |
+
|
2157 |
+
for (int i = m_max_mcus_per_row; i > 0; i--)
|
2158 |
+
{
|
2159 |
+
for (int k = 0; k < m_max_mcu_x_size; k += 8)
|
2160 |
+
{
|
2161 |
+
const int Y_ofs = k * 8;
|
2162 |
+
const int Cb_ofs = Y_ofs + 64 * m_expanded_blocks_per_component;
|
2163 |
+
const int Cr_ofs = Y_ofs + 64 * m_expanded_blocks_per_component * 2;
|
2164 |
+
for (int j = 0; j < 8; j++)
|
2165 |
+
{
|
2166 |
+
int y = Py[Y_ofs + j];
|
2167 |
+
int cb = Py[Cb_ofs + j];
|
2168 |
+
int cr = Py[Cr_ofs + j];
|
2169 |
+
|
2170 |
+
if (jpg_format == ERGBFormatJPG::BGRA)
|
2171 |
+
{
|
2172 |
+
d[0] = clamp(y + m_cbb[cb]);
|
2173 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
2174 |
+
d[2] = clamp(y + m_crr[cr]);
|
2175 |
+
d[3] = 255;
|
2176 |
+
}
|
2177 |
+
else
|
2178 |
+
{
|
2179 |
+
d[0] = clamp(y + m_crr[cr]);
|
2180 |
+
d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
|
2181 |
+
d[2] = clamp(y + m_cbb[cb]);
|
2182 |
+
d[3] = 255;
|
2183 |
+
}
|
2184 |
+
|
2185 |
+
d += 4;
|
2186 |
+
}
|
2187 |
+
}
|
2188 |
+
|
2189 |
+
Py += 64 * m_expanded_blocks_per_mcu;
|
2190 |
+
}
|
2191 |
+
}
|
2192 |
+
|
2193 |
+
// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
|
2194 |
+
void jpeg_decoder::find_eoi()
|
2195 |
+
{
|
2196 |
+
if (!m_progressive_flag)
|
2197 |
+
{
|
2198 |
+
// Attempt to read the EOI marker.
|
2199 |
+
//get_bits_no_markers(m_bits_left & 7);
|
2200 |
+
|
2201 |
+
// Prime the bit buffer
|
2202 |
+
m_bits_left = 16;
|
2203 |
+
get_bits(16);
|
2204 |
+
get_bits(16);
|
2205 |
+
|
2206 |
+
// The next marker _should_ be EOI
|
2207 |
+
process_markers();
|
2208 |
+
}
|
2209 |
+
|
2210 |
+
m_total_bytes_read -= m_in_buf_left;
|
2211 |
+
}
|
2212 |
+
|
2213 |
+
int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len)
|
2214 |
+
{
|
2215 |
+
if ((m_error_code) || (!m_ready_flag))
|
2216 |
+
return JPGD_FAILED;
|
2217 |
+
|
2218 |
+
if (m_total_lines_left == 0)
|
2219 |
+
return JPGD_DONE;
|
2220 |
+
|
2221 |
+
if (m_mcu_lines_left == 0)
|
2222 |
+
{
|
2223 |
+
if (setjmp(m_jmp_state))
|
2224 |
+
return JPGD_FAILED;
|
2225 |
+
|
2226 |
+
if (m_progressive_flag)
|
2227 |
+
load_next_row();
|
2228 |
+
else
|
2229 |
+
decode_next_row();
|
2230 |
+
|
2231 |
+
// Find the EOI marker if that was the last row.
|
2232 |
+
if (m_total_lines_left <= m_max_mcu_y_size)
|
2233 |
+
find_eoi();
|
2234 |
+
|
2235 |
+
m_mcu_lines_left = m_max_mcu_y_size;
|
2236 |
+
}
|
2237 |
+
|
2238 |
+
if (m_freq_domain_chroma_upsample)
|
2239 |
+
{
|
2240 |
+
expanded_convert();
|
2241 |
+
*pScan_line = m_pScan_line_0;
|
2242 |
+
}
|
2243 |
+
else
|
2244 |
+
{
|
2245 |
+
switch (m_scan_type)
|
2246 |
+
{
|
2247 |
+
case JPGD_YH2V2:
|
2248 |
+
{
|
2249 |
+
if ((m_mcu_lines_left & 1) == 0)
|
2250 |
+
{
|
2251 |
+
H2V2Convert();
|
2252 |
+
*pScan_line = m_pScan_line_0;
|
2253 |
+
}
|
2254 |
+
else
|
2255 |
+
*pScan_line = m_pScan_line_1;
|
2256 |
+
|
2257 |
+
break;
|
2258 |
+
}
|
2259 |
+
case JPGD_YH2V1:
|
2260 |
+
{
|
2261 |
+
H2V1Convert();
|
2262 |
+
*pScan_line = m_pScan_line_0;
|
2263 |
+
break;
|
2264 |
+
}
|
2265 |
+
case JPGD_YH1V2:
|
2266 |
+
{
|
2267 |
+
if ((m_mcu_lines_left & 1) == 0)
|
2268 |
+
{
|
2269 |
+
H1V2Convert();
|
2270 |
+
*pScan_line = m_pScan_line_0;
|
2271 |
+
}
|
2272 |
+
else
|
2273 |
+
*pScan_line = m_pScan_line_1;
|
2274 |
+
|
2275 |
+
break;
|
2276 |
+
}
|
2277 |
+
case JPGD_YH1V1:
|
2278 |
+
{
|
2279 |
+
H1V1Convert();
|
2280 |
+
*pScan_line = m_pScan_line_0;
|
2281 |
+
break;
|
2282 |
+
}
|
2283 |
+
case JPGD_GRAYSCALE:
|
2284 |
+
{
|
2285 |
+
gray_convert();
|
2286 |
+
*pScan_line = m_pScan_line_0;
|
2287 |
+
|
2288 |
+
break;
|
2289 |
+
}
|
2290 |
+
}
|
2291 |
+
}
|
2292 |
+
|
2293 |
+
*pScan_line_len = m_real_dest_bytes_per_scan_line;
|
2294 |
+
|
2295 |
+
m_mcu_lines_left--;
|
2296 |
+
m_total_lines_left--;
|
2297 |
+
|
2298 |
+
return JPGD_SUCCESS;
|
2299 |
+
}
|
2300 |
+
|
2301 |
+
// Creates the tables needed for efficient Huffman decoding.
|
2302 |
+
void jpeg_decoder::make_huff_table(int index, huff_tables *pH)
|
2303 |
+
{
|
2304 |
+
int p, i, l, si;
|
2305 |
+
uint8 huffsize[257];
|
2306 |
+
uint huffcode[257];
|
2307 |
+
uint code;
|
2308 |
+
uint subtree;
|
2309 |
+
int code_size;
|
2310 |
+
int lastp;
|
2311 |
+
int nextfreeentry;
|
2312 |
+
int currententry;
|
2313 |
+
|
2314 |
+
pH->ac_table = m_huff_ac[index] != 0;
|
2315 |
+
|
2316 |
+
p = 0;
|
2317 |
+
|
2318 |
+
for (l = 1; l <= 16; l++)
|
2319 |
+
{
|
2320 |
+
for (i = 1; i <= m_huff_num[index][l]; i++)
|
2321 |
+
huffsize[p++] = static_cast<uint8>(l);
|
2322 |
+
}
|
2323 |
+
|
2324 |
+
huffsize[p] = 0;
|
2325 |
+
|
2326 |
+
lastp = p;
|
2327 |
+
|
2328 |
+
code = 0;
|
2329 |
+
si = huffsize[0];
|
2330 |
+
p = 0;
|
2331 |
+
|
2332 |
+
while (huffsize[p])
|
2333 |
+
{
|
2334 |
+
while (huffsize[p] == si)
|
2335 |
+
{
|
2336 |
+
huffcode[p++] = code;
|
2337 |
+
code++;
|
2338 |
+
}
|
2339 |
+
|
2340 |
+
code <<= 1;
|
2341 |
+
si++;
|
2342 |
+
}
|
2343 |
+
|
2344 |
+
memset(pH->look_up, 0, sizeof(pH->look_up));
|
2345 |
+
memset(pH->look_up2, 0, sizeof(pH->look_up2));
|
2346 |
+
memset(pH->tree, 0, sizeof(pH->tree));
|
2347 |
+
memset(pH->code_size, 0, sizeof(pH->code_size));
|
2348 |
+
|
2349 |
+
nextfreeentry = -1;
|
2350 |
+
|
2351 |
+
p = 0;
|
2352 |
+
|
2353 |
+
while (p < lastp)
|
2354 |
+
{
|
2355 |
+
i = m_huff_val[index][p];
|
2356 |
+
code = huffcode[p];
|
2357 |
+
code_size = huffsize[p];
|
2358 |
+
|
2359 |
+
pH->code_size[i] = static_cast<uint8>(code_size);
|
2360 |
+
|
2361 |
+
if (code_size <= 8)
|
2362 |
+
{
|
2363 |
+
code <<= (8 - code_size);
|
2364 |
+
|
2365 |
+
for (l = 1 << (8 - code_size); l > 0; l--)
|
2366 |
+
{
|
2367 |
+
JPGD_ASSERT(i < 256);
|
2368 |
+
|
2369 |
+
pH->look_up[code] = i;
|
2370 |
+
|
2371 |
+
bool has_extrabits = false;
|
2372 |
+
int extra_bits = 0;
|
2373 |
+
int num_extra_bits = i & 15;
|
2374 |
+
|
2375 |
+
int bits_to_fetch = code_size;
|
2376 |
+
if (num_extra_bits)
|
2377 |
+
{
|
2378 |
+
int total_codesize = code_size + num_extra_bits;
|
2379 |
+
if (total_codesize <= 8)
|
2380 |
+
{
|
2381 |
+
has_extrabits = true;
|
2382 |
+
extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize));
|
2383 |
+
JPGD_ASSERT(extra_bits <= 0x7FFF);
|
2384 |
+
bits_to_fetch += num_extra_bits;
|
2385 |
+
}
|
2386 |
+
}
|
2387 |
+
|
2388 |
+
if (!has_extrabits)
|
2389 |
+
pH->look_up2[code] = i | (bits_to_fetch << 8);
|
2390 |
+
else
|
2391 |
+
pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8);
|
2392 |
+
|
2393 |
+
code++;
|
2394 |
+
}
|
2395 |
+
}
|
2396 |
+
else
|
2397 |
+
{
|
2398 |
+
subtree = (code >> (code_size - 8)) & 0xFF;
|
2399 |
+
|
2400 |
+
currententry = pH->look_up[subtree];
|
2401 |
+
|
2402 |
+
if (currententry == 0)
|
2403 |
+
{
|
2404 |
+
pH->look_up[subtree] = currententry = nextfreeentry;
|
2405 |
+
pH->look_up2[subtree] = currententry = nextfreeentry;
|
2406 |
+
|
2407 |
+
nextfreeentry -= 2;
|
2408 |
+
}
|
2409 |
+
|
2410 |
+
code <<= (16 - (code_size - 8));
|
2411 |
+
|
2412 |
+
for (l = code_size; l > 9; l--)
|
2413 |
+
{
|
2414 |
+
if ((code & 0x8000) == 0)
|
2415 |
+
currententry--;
|
2416 |
+
|
2417 |
+
if (pH->tree[-currententry - 1] == 0)
|
2418 |
+
{
|
2419 |
+
pH->tree[-currententry - 1] = nextfreeentry;
|
2420 |
+
|
2421 |
+
currententry = nextfreeentry;
|
2422 |
+
|
2423 |
+
nextfreeentry -= 2;
|
2424 |
+
}
|
2425 |
+
else
|
2426 |
+
currententry = pH->tree[-currententry - 1];
|
2427 |
+
|
2428 |
+
code <<= 1;
|
2429 |
+
}
|
2430 |
+
|
2431 |
+
if ((code & 0x8000) == 0)
|
2432 |
+
currententry--;
|
2433 |
+
|
2434 |
+
pH->tree[-currententry - 1] = i;
|
2435 |
+
}
|
2436 |
+
|
2437 |
+
p++;
|
2438 |
+
}
|
2439 |
+
}
|
2440 |
+
|
2441 |
+
// Verifies the quantization tables needed for this scan are available.
|
2442 |
+
void jpeg_decoder::check_quant_tables()
|
2443 |
+
{
|
2444 |
+
for (int i = 0; i < m_comps_in_scan; i++)
|
2445 |
+
if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL)
|
2446 |
+
stop_decoding(JPGD_UNDEFINED_QUANT_TABLE);
|
2447 |
+
}
|
2448 |
+
|
2449 |
+
// Verifies that all the Huffman tables needed for this scan are available.
|
2450 |
+
void jpeg_decoder::check_huff_tables()
|
2451 |
+
{
|
2452 |
+
for (int i = 0; i < m_comps_in_scan; i++)
|
2453 |
+
{
|
2454 |
+
if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL))
|
2455 |
+
stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
|
2456 |
+
|
2457 |
+
if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL))
|
2458 |
+
stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
|
2459 |
+
}
|
2460 |
+
|
2461 |
+
for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++)
|
2462 |
+
if (m_huff_num[i])
|
2463 |
+
{
|
2464 |
+
if (!m_pHuff_tabs[i])
|
2465 |
+
m_pHuff_tabs[i] = (huff_tables *)alloc(sizeof(huff_tables));
|
2466 |
+
|
2467 |
+
make_huff_table(i, m_pHuff_tabs[i]);
|
2468 |
+
}
|
2469 |
+
}
|
2470 |
+
|
2471 |
+
// Determines the component order inside each MCU.
|
2472 |
+
// Also calcs how many MCU's are on each row, etc.
|
2473 |
+
void jpeg_decoder::calc_mcu_block_order()
|
2474 |
+
{
|
2475 |
+
int component_num, component_id;
|
2476 |
+
int max_h_samp = 0, max_v_samp = 0;
|
2477 |
+
|
2478 |
+
for (component_id = 0; component_id < m_comps_in_frame; component_id++)
|
2479 |
+
{
|
2480 |
+
if (m_comp_h_samp[component_id] > max_h_samp)
|
2481 |
+
max_h_samp = m_comp_h_samp[component_id];
|
2482 |
+
|
2483 |
+
if (m_comp_v_samp[component_id] > max_v_samp)
|
2484 |
+
max_v_samp = m_comp_v_samp[component_id];
|
2485 |
+
}
|
2486 |
+
|
2487 |
+
for (component_id = 0; component_id < m_comps_in_frame; component_id++)
|
2488 |
+
{
|
2489 |
+
m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8;
|
2490 |
+
m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8;
|
2491 |
+
}
|
2492 |
+
|
2493 |
+
if (m_comps_in_scan == 1)
|
2494 |
+
{
|
2495 |
+
m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]];
|
2496 |
+
m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]];
|
2497 |
+
}
|
2498 |
+
else
|
2499 |
+
{
|
2500 |
+
m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp;
|
2501 |
+
m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp;
|
2502 |
+
}
|
2503 |
+
|
2504 |
+
if (m_comps_in_scan == 1)
|
2505 |
+
{
|
2506 |
+
m_mcu_org[0] = m_comp_list[0];
|
2507 |
+
|
2508 |
+
m_blocks_per_mcu = 1;
|
2509 |
+
}
|
2510 |
+
else
|
2511 |
+
{
|
2512 |
+
m_blocks_per_mcu = 0;
|
2513 |
+
|
2514 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
2515 |
+
{
|
2516 |
+
int num_blocks;
|
2517 |
+
|
2518 |
+
component_id = m_comp_list[component_num];
|
2519 |
+
|
2520 |
+
num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id];
|
2521 |
+
|
2522 |
+
while (num_blocks--)
|
2523 |
+
m_mcu_org[m_blocks_per_mcu++] = component_id;
|
2524 |
+
}
|
2525 |
+
}
|
2526 |
+
}
|
2527 |
+
|
2528 |
+
// Starts a new scan.
|
2529 |
+
int jpeg_decoder::init_scan()
|
2530 |
+
{
|
2531 |
+
if (!locate_sos_marker())
|
2532 |
+
return JPGD_FALSE;
|
2533 |
+
|
2534 |
+
calc_mcu_block_order();
|
2535 |
+
|
2536 |
+
check_huff_tables();
|
2537 |
+
|
2538 |
+
check_quant_tables();
|
2539 |
+
|
2540 |
+
memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
|
2541 |
+
|
2542 |
+
m_eob_run = 0;
|
2543 |
+
|
2544 |
+
if (m_restart_interval)
|
2545 |
+
{
|
2546 |
+
m_restarts_left = m_restart_interval;
|
2547 |
+
m_next_restart_num = 0;
|
2548 |
+
}
|
2549 |
+
|
2550 |
+
fix_in_buffer();
|
2551 |
+
|
2552 |
+
return JPGD_TRUE;
|
2553 |
+
}
|
2554 |
+
|
2555 |
+
// Starts a frame. Determines if the number of components or sampling factors
|
2556 |
+
// are supported.
|
2557 |
+
void jpeg_decoder::init_frame()
|
2558 |
+
{
|
2559 |
+
int i;
|
2560 |
+
|
2561 |
+
if (m_comps_in_frame == 1)
|
2562 |
+
{
|
2563 |
+
if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1))
|
2564 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
2565 |
+
|
2566 |
+
m_scan_type = JPGD_GRAYSCALE;
|
2567 |
+
m_max_blocks_per_mcu = 1;
|
2568 |
+
m_max_mcu_x_size = 8;
|
2569 |
+
m_max_mcu_y_size = 8;
|
2570 |
+
}
|
2571 |
+
else if (m_comps_in_frame == 3)
|
2572 |
+
{
|
2573 |
+
if ( ((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) ||
|
2574 |
+
((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)) )
|
2575 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
2576 |
+
|
2577 |
+
if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
|
2578 |
+
{
|
2579 |
+
m_scan_type = JPGD_YH1V1;
|
2580 |
+
|
2581 |
+
m_max_blocks_per_mcu = 3;
|
2582 |
+
m_max_mcu_x_size = 8;
|
2583 |
+
m_max_mcu_y_size = 8;
|
2584 |
+
}
|
2585 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
|
2586 |
+
{
|
2587 |
+
m_scan_type = JPGD_YH2V1;
|
2588 |
+
m_max_blocks_per_mcu = 4;
|
2589 |
+
m_max_mcu_x_size = 16;
|
2590 |
+
m_max_mcu_y_size = 8;
|
2591 |
+
}
|
2592 |
+
else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2))
|
2593 |
+
{
|
2594 |
+
m_scan_type = JPGD_YH1V2;
|
2595 |
+
m_max_blocks_per_mcu = 4;
|
2596 |
+
m_max_mcu_x_size = 8;
|
2597 |
+
m_max_mcu_y_size = 16;
|
2598 |
+
}
|
2599 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
|
2600 |
+
{
|
2601 |
+
m_scan_type = JPGD_YH2V2;
|
2602 |
+
m_max_blocks_per_mcu = 6;
|
2603 |
+
m_max_mcu_x_size = 16;
|
2604 |
+
m_max_mcu_y_size = 16;
|
2605 |
+
}
|
2606 |
+
else
|
2607 |
+
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
|
2608 |
+
}
|
2609 |
+
else
|
2610 |
+
stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
|
2611 |
+
|
2612 |
+
m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size;
|
2613 |
+
m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size;
|
2614 |
+
|
2615 |
+
// These values are for the *destination* pixels: after conversion.
|
2616 |
+
if (m_scan_type == JPGD_GRAYSCALE)
|
2617 |
+
m_dest_bytes_per_pixel = 1;
|
2618 |
+
else
|
2619 |
+
m_dest_bytes_per_pixel = 4;
|
2620 |
+
|
2621 |
+
m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel;
|
2622 |
+
|
2623 |
+
m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel);
|
2624 |
+
|
2625 |
+
// Initialize two scan line buffers.
|
2626 |
+
m_pScan_line_0 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
|
2627 |
+
if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2))
|
2628 |
+
m_pScan_line_1 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
|
2629 |
+
|
2630 |
+
m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu;
|
2631 |
+
|
2632 |
+
// Should never happen
|
2633 |
+
if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW)
|
2634 |
+
stop_decoding(JPGD_ASSERTION_ERROR);
|
2635 |
+
|
2636 |
+
// Allocate the coefficient buffer, enough for one MCU
|
2637 |
+
m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t));
|
2638 |
+
|
2639 |
+
for (i = 0; i < m_max_blocks_per_mcu; i++)
|
2640 |
+
m_mcu_block_max_zag[i] = 64;
|
2641 |
+
|
2642 |
+
m_expanded_blocks_per_component = m_comp_h_samp[0] * m_comp_v_samp[0];
|
2643 |
+
m_expanded_blocks_per_mcu = m_expanded_blocks_per_component * m_comps_in_frame;
|
2644 |
+
m_expanded_blocks_per_row = m_max_mcus_per_row * m_expanded_blocks_per_mcu;
|
2645 |
+
// Freq. domain chroma upsampling is only supported for H2V2 subsampling factor.
|
2646 |
+
// BEGIN EPIC MOD
|
2647 |
+
#if JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING
|
2648 |
+
m_freq_domain_chroma_upsample = (m_expanded_blocks_per_mcu == 4*3);
|
2649 |
+
#else
|
2650 |
+
m_freq_domain_chroma_upsample = 0;
|
2651 |
+
#endif
|
2652 |
+
// END EPIC MOD
|
2653 |
+
|
2654 |
+
if (m_freq_domain_chroma_upsample)
|
2655 |
+
m_pSample_buf = (uint8 *)alloc(m_expanded_blocks_per_row * 64);
|
2656 |
+
else
|
2657 |
+
m_pSample_buf = (uint8 *)alloc(m_max_blocks_per_row * 64);
|
2658 |
+
|
2659 |
+
m_total_lines_left = m_image_y_size;
|
2660 |
+
|
2661 |
+
m_mcu_lines_left = 0;
|
2662 |
+
|
2663 |
+
create_look_ups();
|
2664 |
+
}
|
2665 |
+
|
2666 |
+
// The coeff_buf series of methods originally stored the coefficients
|
2667 |
+
// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
|
2668 |
+
// was used to make this process more efficient. Now, we can store the entire
|
2669 |
+
// thing in RAM.
|
2670 |
+
jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y)
|
2671 |
+
{
|
2672 |
+
coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf));
|
2673 |
+
|
2674 |
+
cb->block_num_x = block_num_x;
|
2675 |
+
cb->block_num_y = block_num_y;
|
2676 |
+
cb->block_len_x = block_len_x;
|
2677 |
+
cb->block_len_y = block_len_y;
|
2678 |
+
cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t);
|
2679 |
+
cb->pData = (uint8 *)alloc(cb->block_size * block_num_x * block_num_y, true);
|
2680 |
+
return cb;
|
2681 |
+
}
|
2682 |
+
|
2683 |
+
inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y)
|
2684 |
+
{
|
2685 |
+
JPGD_ASSERT((block_x < cb->block_num_x) && (block_y < cb->block_num_y));
|
2686 |
+
return (jpgd_block_t *)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x));
|
2687 |
+
}
|
2688 |
+
|
2689 |
+
// The following methods decode the various types of m_blocks encountered
|
2690 |
+
// in progressively encoded images.
|
2691 |
+
void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
2692 |
+
{
|
2693 |
+
int s, r;
|
2694 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
|
2695 |
+
|
2696 |
+
if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0)
|
2697 |
+
{
|
2698 |
+
r = pD->get_bits_no_markers(s);
|
2699 |
+
s = HUFF_EXTEND(r, s);
|
2700 |
+
}
|
2701 |
+
|
2702 |
+
pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]);
|
2703 |
+
|
2704 |
+
p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
|
2705 |
+
}
|
2706 |
+
|
2707 |
+
void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
2708 |
+
{
|
2709 |
+
if (pD->get_bits_no_markers(1))
|
2710 |
+
{
|
2711 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
|
2712 |
+
|
2713 |
+
p[0] |= (1 << pD->m_successive_low);
|
2714 |
+
}
|
2715 |
+
}
|
2716 |
+
|
2717 |
+
void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
2718 |
+
{
|
2719 |
+
int k, s, r;
|
2720 |
+
|
2721 |
+
if (pD->m_eob_run)
|
2722 |
+
{
|
2723 |
+
pD->m_eob_run--;
|
2724 |
+
return;
|
2725 |
+
}
|
2726 |
+
|
2727 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
|
2728 |
+
|
2729 |
+
for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++)
|
2730 |
+
{
|
2731 |
+
s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
|
2732 |
+
|
2733 |
+
r = s >> 4;
|
2734 |
+
s &= 15;
|
2735 |
+
|
2736 |
+
if (s)
|
2737 |
+
{
|
2738 |
+
if ((k += r) > 63)
|
2739 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
2740 |
+
|
2741 |
+
r = pD->get_bits_no_markers(s);
|
2742 |
+
s = HUFF_EXTEND(r, s);
|
2743 |
+
|
2744 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
|
2745 |
+
}
|
2746 |
+
else
|
2747 |
+
{
|
2748 |
+
if (r == 15)
|
2749 |
+
{
|
2750 |
+
if ((k += 15) > 63)
|
2751 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
2752 |
+
}
|
2753 |
+
else
|
2754 |
+
{
|
2755 |
+
pD->m_eob_run = 1 << r;
|
2756 |
+
|
2757 |
+
if (r)
|
2758 |
+
pD->m_eob_run += pD->get_bits_no_markers(r);
|
2759 |
+
|
2760 |
+
pD->m_eob_run--;
|
2761 |
+
|
2762 |
+
break;
|
2763 |
+
}
|
2764 |
+
}
|
2765 |
+
}
|
2766 |
+
}
|
2767 |
+
|
2768 |
+
void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
|
2769 |
+
{
|
2770 |
+
int s, k, r;
|
2771 |
+
int p1 = 1 << pD->m_successive_low;
|
2772 |
+
int m1 = (-1) << pD->m_successive_low;
|
2773 |
+
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
|
2774 |
+
|
2775 |
+
k = pD->m_spectral_start;
|
2776 |
+
|
2777 |
+
if (pD->m_eob_run == 0)
|
2778 |
+
{
|
2779 |
+
for ( ; k <= pD->m_spectral_end; k++)
|
2780 |
+
{
|
2781 |
+
s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
|
2782 |
+
|
2783 |
+
r = s >> 4;
|
2784 |
+
s &= 15;
|
2785 |
+
|
2786 |
+
if (s)
|
2787 |
+
{
|
2788 |
+
if (s != 1)
|
2789 |
+
pD->stop_decoding(JPGD_DECODE_ERROR);
|
2790 |
+
|
2791 |
+
if (pD->get_bits_no_markers(1))
|
2792 |
+
s = p1;
|
2793 |
+
else
|
2794 |
+
s = m1;
|
2795 |
+
}
|
2796 |
+
else
|
2797 |
+
{
|
2798 |
+
if (r != 15)
|
2799 |
+
{
|
2800 |
+
pD->m_eob_run = 1 << r;
|
2801 |
+
|
2802 |
+
if (r)
|
2803 |
+
pD->m_eob_run += pD->get_bits_no_markers(r);
|
2804 |
+
|
2805 |
+
break;
|
2806 |
+
}
|
2807 |
+
}
|
2808 |
+
|
2809 |
+
do
|
2810 |
+
{
|
2811 |
+
// BEGIN EPIC MOD
|
2812 |
+
JPGD_ASSERT(k < 64);
|
2813 |
+
// END EPIC MOD
|
2814 |
+
|
2815 |
+
jpgd_block_t *this_coef = p + g_ZAG[k];
|
2816 |
+
|
2817 |
+
if (*this_coef != 0)
|
2818 |
+
{
|
2819 |
+
if (pD->get_bits_no_markers(1))
|
2820 |
+
{
|
2821 |
+
if ((*this_coef & p1) == 0)
|
2822 |
+
{
|
2823 |
+
if (*this_coef >= 0)
|
2824 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
|
2825 |
+
else
|
2826 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
|
2827 |
+
}
|
2828 |
+
}
|
2829 |
+
}
|
2830 |
+
else
|
2831 |
+
{
|
2832 |
+
if (--r < 0)
|
2833 |
+
break;
|
2834 |
+
}
|
2835 |
+
|
2836 |
+
k++;
|
2837 |
+
|
2838 |
+
} while (k <= pD->m_spectral_end);
|
2839 |
+
|
2840 |
+
if ((s) && (k < 64))
|
2841 |
+
{
|
2842 |
+
p[g_ZAG[k]] = static_cast<jpgd_block_t>(s);
|
2843 |
+
}
|
2844 |
+
}
|
2845 |
+
}
|
2846 |
+
|
2847 |
+
if (pD->m_eob_run > 0)
|
2848 |
+
{
|
2849 |
+
for ( ; k <= pD->m_spectral_end; k++)
|
2850 |
+
{
|
2851 |
+
// BEGIN EPIC MOD
|
2852 |
+
JPGD_ASSERT(k < 64);
|
2853 |
+
// END EPIC MOD
|
2854 |
+
|
2855 |
+
jpgd_block_t *this_coef = p + g_ZAG[k];
|
2856 |
+
|
2857 |
+
if (*this_coef != 0)
|
2858 |
+
{
|
2859 |
+
if (pD->get_bits_no_markers(1))
|
2860 |
+
{
|
2861 |
+
if ((*this_coef & p1) == 0)
|
2862 |
+
{
|
2863 |
+
if (*this_coef >= 0)
|
2864 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
|
2865 |
+
else
|
2866 |
+
*this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
|
2867 |
+
}
|
2868 |
+
}
|
2869 |
+
}
|
2870 |
+
}
|
2871 |
+
|
2872 |
+
pD->m_eob_run--;
|
2873 |
+
}
|
2874 |
+
}
|
2875 |
+
|
2876 |
+
// Decode a scan in a progressively encoded image.
|
2877 |
+
void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func)
|
2878 |
+
{
|
2879 |
+
int mcu_row, mcu_col, mcu_block;
|
2880 |
+
int block_x_mcu[JPGD_MAX_COMPONENTS], m_block_y_mcu[JPGD_MAX_COMPONENTS];
|
2881 |
+
|
2882 |
+
memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
|
2883 |
+
|
2884 |
+
for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++)
|
2885 |
+
{
|
2886 |
+
int component_num, component_id;
|
2887 |
+
|
2888 |
+
memset(block_x_mcu, 0, sizeof(block_x_mcu));
|
2889 |
+
|
2890 |
+
for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
|
2891 |
+
{
|
2892 |
+
int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
|
2893 |
+
|
2894 |
+
if ((m_restart_interval) && (m_restarts_left == 0))
|
2895 |
+
process_restart();
|
2896 |
+
|
2897 |
+
for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
|
2898 |
+
{
|
2899 |
+
component_id = m_mcu_org[mcu_block];
|
2900 |
+
|
2901 |
+
decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
|
2902 |
+
|
2903 |
+
if (m_comps_in_scan == 1)
|
2904 |
+
block_x_mcu[component_id]++;
|
2905 |
+
else
|
2906 |
+
{
|
2907 |
+
if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
|
2908 |
+
{
|
2909 |
+
block_x_mcu_ofs = 0;
|
2910 |
+
|
2911 |
+
if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
|
2912 |
+
{
|
2913 |
+
block_y_mcu_ofs = 0;
|
2914 |
+
block_x_mcu[component_id] += m_comp_h_samp[component_id];
|
2915 |
+
}
|
2916 |
+
}
|
2917 |
+
}
|
2918 |
+
}
|
2919 |
+
|
2920 |
+
m_restarts_left--;
|
2921 |
+
}
|
2922 |
+
|
2923 |
+
if (m_comps_in_scan == 1)
|
2924 |
+
m_block_y_mcu[m_comp_list[0]]++;
|
2925 |
+
else
|
2926 |
+
{
|
2927 |
+
for (component_num = 0; component_num < m_comps_in_scan; component_num++)
|
2928 |
+
{
|
2929 |
+
component_id = m_comp_list[component_num];
|
2930 |
+
m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
|
2931 |
+
}
|
2932 |
+
}
|
2933 |
+
}
|
2934 |
+
}
|
2935 |
+
|
2936 |
+
// Decode a progressively encoded image.
|
2937 |
+
void jpeg_decoder::init_progressive()
|
2938 |
+
{
|
2939 |
+
int i;
|
2940 |
+
|
2941 |
+
if (m_comps_in_frame == 4)
|
2942 |
+
stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
|
2943 |
+
|
2944 |
+
// Allocate the coefficient buffers.
|
2945 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
2946 |
+
{
|
2947 |
+
m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1);
|
2948 |
+
m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8);
|
2949 |
+
}
|
2950 |
+
|
2951 |
+
for ( ; ; )
|
2952 |
+
{
|
2953 |
+
int dc_only_scan, refinement_scan;
|
2954 |
+
pDecode_block_func decode_block_func;
|
2955 |
+
|
2956 |
+
if (!init_scan())
|
2957 |
+
break;
|
2958 |
+
|
2959 |
+
dc_only_scan = (m_spectral_start == 0);
|
2960 |
+
refinement_scan = (m_successive_high != 0);
|
2961 |
+
|
2962 |
+
if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63))
|
2963 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
2964 |
+
|
2965 |
+
if (dc_only_scan)
|
2966 |
+
{
|
2967 |
+
if (m_spectral_end)
|
2968 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
2969 |
+
}
|
2970 |
+
else if (m_comps_in_scan != 1) /* AC scans can only contain one component */
|
2971 |
+
stop_decoding(JPGD_BAD_SOS_SPECTRAL);
|
2972 |
+
|
2973 |
+
if ((refinement_scan) && (m_successive_low != m_successive_high - 1))
|
2974 |
+
stop_decoding(JPGD_BAD_SOS_SUCCESSIVE);
|
2975 |
+
|
2976 |
+
if (dc_only_scan)
|
2977 |
+
{
|
2978 |
+
if (refinement_scan)
|
2979 |
+
decode_block_func = decode_block_dc_refine;
|
2980 |
+
else
|
2981 |
+
decode_block_func = decode_block_dc_first;
|
2982 |
+
}
|
2983 |
+
else
|
2984 |
+
{
|
2985 |
+
if (refinement_scan)
|
2986 |
+
decode_block_func = decode_block_ac_refine;
|
2987 |
+
else
|
2988 |
+
decode_block_func = decode_block_ac_first;
|
2989 |
+
}
|
2990 |
+
|
2991 |
+
decode_scan(decode_block_func);
|
2992 |
+
|
2993 |
+
m_bits_left = 16;
|
2994 |
+
get_bits(16);
|
2995 |
+
get_bits(16);
|
2996 |
+
}
|
2997 |
+
|
2998 |
+
m_comps_in_scan = m_comps_in_frame;
|
2999 |
+
|
3000 |
+
for (i = 0; i < m_comps_in_frame; i++)
|
3001 |
+
m_comp_list[i] = i;
|
3002 |
+
|
3003 |
+
calc_mcu_block_order();
|
3004 |
+
}
|
3005 |
+
|
3006 |
+
void jpeg_decoder::init_sequential()
|
3007 |
+
{
|
3008 |
+
if (!init_scan())
|
3009 |
+
stop_decoding(JPGD_UNEXPECTED_MARKER);
|
3010 |
+
}
|
3011 |
+
|
3012 |
+
void jpeg_decoder::decode_start()
|
3013 |
+
{
|
3014 |
+
init_frame();
|
3015 |
+
|
3016 |
+
if (m_progressive_flag)
|
3017 |
+
init_progressive();
|
3018 |
+
else
|
3019 |
+
init_sequential();
|
3020 |
+
}
|
3021 |
+
|
3022 |
+
void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream)
|
3023 |
+
{
|
3024 |
+
init(pStream);
|
3025 |
+
locate_sof_marker();
|
3026 |
+
}
|
3027 |
+
|
3028 |
+
jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream)
|
3029 |
+
{
|
3030 |
+
if (setjmp(m_jmp_state))
|
3031 |
+
return;
|
3032 |
+
decode_init(pStream);
|
3033 |
+
}
|
3034 |
+
|
3035 |
+
int jpeg_decoder::begin_decoding()
|
3036 |
+
{
|
3037 |
+
if (m_ready_flag)
|
3038 |
+
return JPGD_SUCCESS;
|
3039 |
+
|
3040 |
+
if (m_error_code)
|
3041 |
+
return JPGD_FAILED;
|
3042 |
+
|
3043 |
+
if (setjmp(m_jmp_state))
|
3044 |
+
return JPGD_FAILED;
|
3045 |
+
|
3046 |
+
decode_start();
|
3047 |
+
|
3048 |
+
m_ready_flag = true;
|
3049 |
+
|
3050 |
+
return JPGD_SUCCESS;
|
3051 |
+
}
|
3052 |
+
|
3053 |
+
jpeg_decoder::~jpeg_decoder()
|
3054 |
+
{
|
3055 |
+
free_all_blocks();
|
3056 |
+
}
|
3057 |
+
|
3058 |
+
jpeg_decoder_file_stream::jpeg_decoder_file_stream()
|
3059 |
+
{
|
3060 |
+
m_pFile = NULL;
|
3061 |
+
m_eof_flag = false;
|
3062 |
+
m_error_flag = false;
|
3063 |
+
}
|
3064 |
+
|
3065 |
+
void jpeg_decoder_file_stream::close()
|
3066 |
+
{
|
3067 |
+
if (m_pFile)
|
3068 |
+
{
|
3069 |
+
fclose(m_pFile);
|
3070 |
+
m_pFile = NULL;
|
3071 |
+
}
|
3072 |
+
|
3073 |
+
m_eof_flag = false;
|
3074 |
+
m_error_flag = false;
|
3075 |
+
}
|
3076 |
+
|
3077 |
+
jpeg_decoder_file_stream::~jpeg_decoder_file_stream()
|
3078 |
+
{
|
3079 |
+
close();
|
3080 |
+
}
|
3081 |
+
|
3082 |
+
bool jpeg_decoder_file_stream::open(const char *Pfilename)
|
3083 |
+
{
|
3084 |
+
close();
|
3085 |
+
|
3086 |
+
m_eof_flag = false;
|
3087 |
+
m_error_flag = false;
|
3088 |
+
|
3089 |
+
#if defined(_MSC_VER)
|
3090 |
+
m_pFile = NULL;
|
3091 |
+
fopen_s(&m_pFile, Pfilename, "rb");
|
3092 |
+
#else
|
3093 |
+
m_pFile = fopen(Pfilename, "rb");
|
3094 |
+
#endif
|
3095 |
+
return m_pFile != NULL;
|
3096 |
+
}
|
3097 |
+
|
3098 |
+
int jpeg_decoder_file_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
|
3099 |
+
{
|
3100 |
+
if (!m_pFile)
|
3101 |
+
return -1;
|
3102 |
+
|
3103 |
+
if (m_eof_flag)
|
3104 |
+
{
|
3105 |
+
*pEOF_flag = true;
|
3106 |
+
return 0;
|
3107 |
+
}
|
3108 |
+
|
3109 |
+
if (m_error_flag)
|
3110 |
+
return -1;
|
3111 |
+
|
3112 |
+
int bytes_read = static_cast<int>(fread(pBuf, 1, max_bytes_to_read, m_pFile));
|
3113 |
+
if (bytes_read < max_bytes_to_read)
|
3114 |
+
{
|
3115 |
+
if (ferror(m_pFile))
|
3116 |
+
{
|
3117 |
+
m_error_flag = true;
|
3118 |
+
return -1;
|
3119 |
+
}
|
3120 |
+
|
3121 |
+
m_eof_flag = true;
|
3122 |
+
*pEOF_flag = true;
|
3123 |
+
}
|
3124 |
+
|
3125 |
+
return bytes_read;
|
3126 |
+
}
|
3127 |
+
|
3128 |
+
bool jpeg_decoder_mem_stream::open(const uint8 *pSrc_data, uint size)
|
3129 |
+
{
|
3130 |
+
close();
|
3131 |
+
m_pSrc_data = pSrc_data;
|
3132 |
+
m_ofs = 0;
|
3133 |
+
m_size = size;
|
3134 |
+
return true;
|
3135 |
+
}
|
3136 |
+
|
3137 |
+
int jpeg_decoder_mem_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
|
3138 |
+
{
|
3139 |
+
*pEOF_flag = false;
|
3140 |
+
|
3141 |
+
if (!m_pSrc_data)
|
3142 |
+
return -1;
|
3143 |
+
|
3144 |
+
uint bytes_remaining = m_size - m_ofs;
|
3145 |
+
if ((uint)max_bytes_to_read > bytes_remaining)
|
3146 |
+
{
|
3147 |
+
max_bytes_to_read = bytes_remaining;
|
3148 |
+
*pEOF_flag = true;
|
3149 |
+
}
|
3150 |
+
|
3151 |
+
memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read);
|
3152 |
+
m_ofs += max_bytes_to_read;
|
3153 |
+
|
3154 |
+
return max_bytes_to_read;
|
3155 |
+
}
|
3156 |
+
|
3157 |
+
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps)
|
3158 |
+
{
|
3159 |
+
if (!actual_comps)
|
3160 |
+
return NULL;
|
3161 |
+
*actual_comps = 0;
|
3162 |
+
|
3163 |
+
if ((!pStream) || (!width) || (!height) || (!req_comps))
|
3164 |
+
return NULL;
|
3165 |
+
|
3166 |
+
if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4))
|
3167 |
+
return NULL;
|
3168 |
+
|
3169 |
+
jpeg_decoder decoder(pStream);
|
3170 |
+
if (decoder.get_error_code() != JPGD_SUCCESS)
|
3171 |
+
return NULL;
|
3172 |
+
|
3173 |
+
const int image_width = decoder.get_width(), image_height = decoder.get_height();
|
3174 |
+
*width = image_width;
|
3175 |
+
*height = image_height;
|
3176 |
+
*actual_comps = decoder.get_num_components();
|
3177 |
+
|
3178 |
+
if (decoder.begin_decoding() != JPGD_SUCCESS)
|
3179 |
+
return NULL;
|
3180 |
+
|
3181 |
+
const int dst_bpl = image_width * req_comps;
|
3182 |
+
|
3183 |
+
uint8 *pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height);
|
3184 |
+
if (!pImage_data)
|
3185 |
+
return NULL;
|
3186 |
+
|
3187 |
+
for (int y = 0; y < image_height; y++)
|
3188 |
+
{
|
3189 |
+
const uint8* pScan_line = 0;
|
3190 |
+
uint scan_line_len;
|
3191 |
+
if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS)
|
3192 |
+
{
|
3193 |
+
jpgd_free(pImage_data);
|
3194 |
+
return NULL;
|
3195 |
+
}
|
3196 |
+
|
3197 |
+
uint8 *pDst = pImage_data + y * dst_bpl;
|
3198 |
+
|
3199 |
+
if (((req_comps == 4) && (decoder.get_num_components() == 3)) ||
|
3200 |
+
((req_comps == 1) && (decoder.get_num_components() == 1)))
|
3201 |
+
{
|
3202 |
+
memcpy(pDst, pScan_line, dst_bpl);
|
3203 |
+
}
|
3204 |
+
else if (decoder.get_num_components() == 1)
|
3205 |
+
{
|
3206 |
+
if (req_comps == 3)
|
3207 |
+
{
|
3208 |
+
for (int x = 0; x < image_width; x++)
|
3209 |
+
{
|
3210 |
+
uint8 luma = pScan_line[x];
|
3211 |
+
pDst[0] = luma;
|
3212 |
+
pDst[1] = luma;
|
3213 |
+
pDst[2] = luma;
|
3214 |
+
pDst += 3;
|
3215 |
+
}
|
3216 |
+
}
|
3217 |
+
else
|
3218 |
+
{
|
3219 |
+
for (int x = 0; x < image_width; x++)
|
3220 |
+
{
|
3221 |
+
uint8 luma = pScan_line[x];
|
3222 |
+
pDst[0] = luma;
|
3223 |
+
pDst[1] = luma;
|
3224 |
+
pDst[2] = luma;
|
3225 |
+
pDst[3] = 255;
|
3226 |
+
pDst += 4;
|
3227 |
+
}
|
3228 |
+
}
|
3229 |
+
}
|
3230 |
+
else if (decoder.get_num_components() == 3)
|
3231 |
+
{
|
3232 |
+
if (req_comps == 1)
|
3233 |
+
{
|
3234 |
+
const int YR = 19595, YG = 38470, YB = 7471;
|
3235 |
+
for (int x = 0; x < image_width; x++)
|
3236 |
+
{
|
3237 |
+
int r = pScan_line[x*4+0];
|
3238 |
+
int g = pScan_line[x*4+1];
|
3239 |
+
int b = pScan_line[x*4+2];
|
3240 |
+
*pDst++ = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
3241 |
+
}
|
3242 |
+
}
|
3243 |
+
else
|
3244 |
+
{
|
3245 |
+
for (int x = 0; x < image_width; x++)
|
3246 |
+
{
|
3247 |
+
pDst[0] = pScan_line[x*4+0];
|
3248 |
+
pDst[1] = pScan_line[x*4+1];
|
3249 |
+
pDst[2] = pScan_line[x*4+2];
|
3250 |
+
pDst += 3;
|
3251 |
+
}
|
3252 |
+
}
|
3253 |
+
}
|
3254 |
+
}
|
3255 |
+
|
3256 |
+
return pImage_data;
|
3257 |
+
}
|
3258 |
+
|
3259 |
+
// BEGIN EPIC MOD
|
3260 |
+
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps, int format)
|
3261 |
+
{
|
3262 |
+
jpg_format = (ERGBFormatJPG)format;
|
3263 |
+
// EMD EPIC MOD
|
3264 |
+
jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
|
3265 |
+
return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps);
|
3266 |
+
}
|
3267 |
+
|
3268 |
+
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps)
|
3269 |
+
{
|
3270 |
+
jpgd::jpeg_decoder_file_stream file_stream;
|
3271 |
+
if (!file_stream.open(pSrc_filename))
|
3272 |
+
return NULL;
|
3273 |
+
return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps);
|
3274 |
+
}
|
3275 |
+
|
3276 |
+
} // namespace jpgd
|
crazy_functions/test_project/cpp/longcode/jpge.cpp
ADDED
@@ -0,0 +1,1049 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// jpge.cpp - C++ class for JPEG compression.
|
2 |
+
// Public domain, Rich Geldreich <richgel99@gmail.com>
|
3 |
+
// v1.01, Dec. 18, 2010 - Initial release
|
4 |
+
// v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.)
|
5 |
+
// v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc.
|
6 |
+
// Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03).
|
7 |
+
// v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug.
|
8 |
+
// Code tweaks to fix VS2008 static code analysis warnings (all looked harmless).
|
9 |
+
// Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02.
|
10 |
+
|
11 |
+
#include "jpge.h"
|
12 |
+
|
13 |
+
#include <stdlib.h>
|
14 |
+
#include <string.h>
|
15 |
+
#if PLATFORM_WINDOWS
|
16 |
+
#include <malloc.h>
|
17 |
+
#endif
|
18 |
+
|
19 |
+
#define JPGE_MAX(a,b) (((a)>(b))?(a):(b))
|
20 |
+
#define JPGE_MIN(a,b) (((a)<(b))?(a):(b))
|
21 |
+
|
22 |
+
namespace jpge {
|
23 |
+
|
24 |
+
static inline void *jpge_malloc(size_t nSize) { return FMemory::Malloc(nSize); }
|
25 |
+
static inline void jpge_free(void *p) { FMemory::Free(p);; }
|
26 |
+
|
27 |
+
// Various JPEG enums and tables.
|
28 |
+
enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 };
|
29 |
+
enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 };
|
30 |
+
|
31 |
+
static uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
|
32 |
+
static int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 };
|
33 |
+
static int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 };
|
34 |
+
static uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
|
35 |
+
static uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
36 |
+
static uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
|
37 |
+
static uint8 s_ac_lum_val[AC_LUM_CODES] =
|
38 |
+
{
|
39 |
+
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
|
40 |
+
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
|
41 |
+
0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
|
42 |
+
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
|
43 |
+
0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
44 |
+
0xf9,0xfa
|
45 |
+
};
|
46 |
+
static uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
|
47 |
+
static uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
|
48 |
+
static uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
|
49 |
+
static uint8 s_ac_chroma_val[AC_CHROMA_CODES] =
|
50 |
+
{
|
51 |
+
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
|
52 |
+
0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
|
53 |
+
0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
|
54 |
+
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
|
55 |
+
0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
|
56 |
+
0xf9,0xfa
|
57 |
+
};
|
58 |
+
|
59 |
+
// Low-level helper functions.
|
60 |
+
template <class T> inline void clear_obj(T &obj) { memset(&obj, 0, sizeof(obj)); }
|
61 |
+
|
62 |
+
const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
|
63 |
+
static inline uint8 clamp(int i) { if (static_cast<uint>(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return static_cast<uint8>(i); }
|
64 |
+
|
65 |
+
static void RGB_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
66 |
+
{
|
67 |
+
for ( ; num_pixels; pDst += 3, pSrc += 3, num_pixels--)
|
68 |
+
{
|
69 |
+
const int r = pSrc[0], g = pSrc[1], b = pSrc[2];
|
70 |
+
pDst[0] = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
71 |
+
pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
72 |
+
pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
static void RGB_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
77 |
+
{
|
78 |
+
for ( ; num_pixels; pDst++, pSrc += 3, num_pixels--)
|
79 |
+
pDst[0] = static_cast<uint8>((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16);
|
80 |
+
}
|
81 |
+
|
82 |
+
static void RGBA_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
83 |
+
{
|
84 |
+
for ( ; num_pixels; pDst += 3, pSrc += 4, num_pixels--)
|
85 |
+
{
|
86 |
+
const int r = pSrc[0], g = pSrc[1], b = pSrc[2];
|
87 |
+
pDst[0] = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
|
88 |
+
pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
|
89 |
+
pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
static void RGBA_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels)
|
94 |
+
{
|
95 |
+
for ( ; num_pixels; pDst++, pSrc += 4, num_pixels--)
|
96 |
+
pDst[0] = static_cast<uint8>((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16);
|
97 |
+
}
|
98 |
+
|
99 |
+
static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels)
|
100 |
+
{
|
101 |
+
for( ; num_pixels; pDst += 3, pSrc++, num_pixels--) { pDst[0] = pSrc[0]; pDst[1] = 128; pDst[2] = 128; }
|
102 |
+
}
|
103 |
+
|
104 |
+
// Forward DCT - DCT derived from jfdctint.
|
105 |
+
#define CONST_BITS 13
|
106 |
+
#define ROW_BITS 2
|
107 |
+
#define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n))
|
108 |
+
#define DCT_MUL(var, c) (static_cast<int16>(var) * static_cast<int32>(c))
|
109 |
+
#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \
|
110 |
+
int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \
|
111 |
+
int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \
|
112 |
+
int32 u1 = DCT_MUL(t12 + t13, 4433); \
|
113 |
+
s2 = u1 + DCT_MUL(t13, 6270); \
|
114 |
+
s6 = u1 + DCT_MUL(t12, -15137); \
|
115 |
+
u1 = t4 + t7; \
|
116 |
+
int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \
|
117 |
+
int32 z5 = DCT_MUL(u3 + u4, 9633); \
|
118 |
+
t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \
|
119 |
+
t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \
|
120 |
+
u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \
|
121 |
+
u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \
|
122 |
+
u3 += z5; u4 += z5; \
|
123 |
+
s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3;
|
124 |
+
|
125 |
+
static void DCT2D(int32 *p)
|
126 |
+
{
|
127 |
+
int32 c, *q = p;
|
128 |
+
for (c = 7; c >= 0; c--, q += 8)
|
129 |
+
{
|
130 |
+
int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7];
|
131 |
+
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
132 |
+
q[0] = s0 << ROW_BITS; q[1] = DCT_DESCALE(s1, CONST_BITS-ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS-ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS-ROW_BITS);
|
133 |
+
q[4] = s4 << ROW_BITS; q[5] = DCT_DESCALE(s5, CONST_BITS-ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS-ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS-ROW_BITS);
|
134 |
+
}
|
135 |
+
for (q = p, c = 7; c >= 0; c--, q++)
|
136 |
+
{
|
137 |
+
int32 s0 = q[0*8], s1 = q[1*8], s2 = q[2*8], s3 = q[3*8], s4 = q[4*8], s5 = q[5*8], s6 = q[6*8], s7 = q[7*8];
|
138 |
+
DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
|
139 |
+
q[0*8] = DCT_DESCALE(s0, ROW_BITS+3); q[1*8] = DCT_DESCALE(s1, CONST_BITS+ROW_BITS+3); q[2*8] = DCT_DESCALE(s2, CONST_BITS+ROW_BITS+3); q[3*8] = DCT_DESCALE(s3, CONST_BITS+ROW_BITS+3);
|
140 |
+
q[4*8] = DCT_DESCALE(s4, ROW_BITS+3); q[5*8] = DCT_DESCALE(s5, CONST_BITS+ROW_BITS+3); q[6*8] = DCT_DESCALE(s6, CONST_BITS+ROW_BITS+3); q[7*8] = DCT_DESCALE(s7, CONST_BITS+ROW_BITS+3);
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
struct sym_freq { uint m_key, m_sym_index; };
|
145 |
+
|
146 |
+
// Radix sorts sym_freq[] array by 32-bit key m_key. Returns ptr to sorted values.
|
147 |
+
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* pSyms0, sym_freq* pSyms1)
|
148 |
+
{
|
149 |
+
const uint cMaxPasses = 4;
|
150 |
+
uint32 hist[256 * cMaxPasses]; clear_obj(hist);
|
151 |
+
for (uint i = 0; i < num_syms; i++) { uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; hist[256*2 + ((freq >> 16) & 0xFF)]++; hist[256*3 + ((freq >> 24) & 0xFF)]++; }
|
152 |
+
sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1;
|
153 |
+
uint total_passes = cMaxPasses; while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
|
154 |
+
for (uint pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
|
155 |
+
{
|
156 |
+
const uint32* pHist = &hist[pass << 8];
|
157 |
+
uint offsets[256], cur_ofs = 0;
|
158 |
+
for (uint i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
|
159 |
+
for (uint i = 0; i < num_syms; i++)
|
160 |
+
pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
|
161 |
+
sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t;
|
162 |
+
}
|
163 |
+
return pCur_syms;
|
164 |
+
}
|
165 |
+
|
166 |
+
// calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
|
167 |
+
static void calculate_minimum_redundancy(sym_freq *A, int n)
|
168 |
+
{
|
169 |
+
int root, leaf, next, avbl, used, dpth;
|
170 |
+
if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
|
171 |
+
A[0].m_key += A[1].m_key; root = 0; leaf = 2;
|
172 |
+
for (next=1; next < n-1; next++)
|
173 |
+
{
|
174 |
+
if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = next; } else A[next].m_key = A[leaf++].m_key;
|
175 |
+
if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key += A[root].m_key; A[root++].m_key = next; } else A[next].m_key += A[leaf++].m_key;
|
176 |
+
}
|
177 |
+
A[n-2].m_key = 0;
|
178 |
+
for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1;
|
179 |
+
avbl = 1; used = dpth = 0; root = n-2; next = n-1;
|
180 |
+
while (avbl>0)
|
181 |
+
{
|
182 |
+
while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
|
183 |
+
while (avbl>used) { A[next--].m_key = dpth; avbl--; }
|
184 |
+
avbl = 2*used; dpth++; used = 0;
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
// Limits canonical Huffman code table's max code size to max_code_size.
|
189 |
+
static void huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
|
190 |
+
{
|
191 |
+
if (code_list_len <= 1) return;
|
192 |
+
|
193 |
+
for (int i = max_code_size + 1; i <= MAX_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
|
194 |
+
|
195 |
+
uint32 total = 0;
|
196 |
+
for (int i = max_code_size; i > 0; i--)
|
197 |
+
total += (((uint32)pNum_codes[i]) << (max_code_size - i));
|
198 |
+
|
199 |
+
while (total != (1UL << max_code_size))
|
200 |
+
{
|
201 |
+
pNum_codes[max_code_size]--;
|
202 |
+
for (int i = max_code_size - 1; i > 0; i--)
|
203 |
+
{
|
204 |
+
if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
|
205 |
+
}
|
206 |
+
total--;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
// Generates an optimized offman table.
|
211 |
+
void jpeg_encoder::optimize_huffman_table(int table_num, int table_len)
|
212 |
+
{
|
213 |
+
sym_freq syms0[MAX_HUFF_SYMBOLS], syms1[MAX_HUFF_SYMBOLS];
|
214 |
+
syms0[0].m_key = 1; syms0[0].m_sym_index = 0; // dummy symbol, assures that no valid code contains all 1's
|
215 |
+
int num_used_syms = 1;
|
216 |
+
const uint32 *pSym_count = &m_huff_count[table_num][0];
|
217 |
+
for (int i = 0; i < table_len; i++)
|
218 |
+
if (pSym_count[i]) { syms0[num_used_syms].m_key = pSym_count[i]; syms0[num_used_syms++].m_sym_index = i + 1; }
|
219 |
+
sym_freq* pSyms = radix_sort_syms(num_used_syms, syms0, syms1);
|
220 |
+
calculate_minimum_redundancy(pSyms, num_used_syms);
|
221 |
+
|
222 |
+
// Count the # of symbols of each code size.
|
223 |
+
int num_codes[1 + MAX_HUFF_CODESIZE]; clear_obj(num_codes);
|
224 |
+
for (int i = 0; i < num_used_syms; i++)
|
225 |
+
num_codes[pSyms[i].m_key]++;
|
226 |
+
|
227 |
+
const uint JPGE_CODE_SIZE_LIMIT = 16; // the maximum possible size of a JPEG Huffman code (valid range is [9,16] - 9 vs. 8 because of the dummy symbol)
|
228 |
+
huffman_enforce_max_code_size(num_codes, num_used_syms, JPGE_CODE_SIZE_LIMIT);
|
229 |
+
|
230 |
+
// Compute m_huff_bits array, which contains the # of symbols per code size.
|
231 |
+
clear_obj(m_huff_bits[table_num]);
|
232 |
+
for (int i = 1; i <= (int)JPGE_CODE_SIZE_LIMIT; i++)
|
233 |
+
m_huff_bits[table_num][i] = static_cast<uint8>(num_codes[i]);
|
234 |
+
|
235 |
+
// Remove the dummy symbol added above, which must be in largest bucket.
|
236 |
+
for (int i = JPGE_CODE_SIZE_LIMIT; i >= 1; i--)
|
237 |
+
{
|
238 |
+
if (m_huff_bits[table_num][i]) { m_huff_bits[table_num][i]--; break; }
|
239 |
+
}
|
240 |
+
|
241 |
+
// Compute the m_huff_val array, which contains the symbol indices sorted by code size (smallest to largest).
|
242 |
+
for (int i = num_used_syms - 1; i >= 1; i--)
|
243 |
+
m_huff_val[table_num][num_used_syms - 1 - i] = static_cast<uint8>(pSyms[i].m_sym_index - 1);
|
244 |
+
}
|
245 |
+
|
246 |
+
// JPEG marker generation.
|
247 |
+
void jpeg_encoder::emit_byte(uint8 i)
|
248 |
+
{
|
249 |
+
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_obj(i);
|
250 |
+
}
|
251 |
+
|
252 |
+
void jpeg_encoder::emit_word(uint i)
|
253 |
+
{
|
254 |
+
emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF));
|
255 |
+
}
|
256 |
+
|
257 |
+
void jpeg_encoder::emit_marker(int marker)
|
258 |
+
{
|
259 |
+
emit_byte(uint8(0xFF)); emit_byte(uint8(marker));
|
260 |
+
}
|
261 |
+
|
262 |
+
// Emit JFIF marker
|
263 |
+
void jpeg_encoder::emit_jfif_app0()
|
264 |
+
{
|
265 |
+
emit_marker(M_APP0);
|
266 |
+
emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1);
|
267 |
+
emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */
|
268 |
+
emit_byte(0);
|
269 |
+
emit_byte(1); /* Major version */
|
270 |
+
emit_byte(1); /* Minor version */
|
271 |
+
emit_byte(0); /* Density unit */
|
272 |
+
emit_word(1);
|
273 |
+
emit_word(1);
|
274 |
+
emit_byte(0); /* No thumbnail image */
|
275 |
+
emit_byte(0);
|
276 |
+
}
|
277 |
+
|
278 |
+
// Emit quantization tables
|
279 |
+
void jpeg_encoder::emit_dqt()
|
280 |
+
{
|
281 |
+
for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++)
|
282 |
+
{
|
283 |
+
emit_marker(M_DQT);
|
284 |
+
emit_word(64 + 1 + 2);
|
285 |
+
emit_byte(static_cast<uint8>(i));
|
286 |
+
for (int j = 0; j < 64; j++)
|
287 |
+
emit_byte(static_cast<uint8>(m_quantization_tables[i][j]));
|
288 |
+
}
|
289 |
+
}
|
290 |
+
|
291 |
+
// Emit start of frame marker
|
292 |
+
void jpeg_encoder::emit_sof()
|
293 |
+
{
|
294 |
+
emit_marker(M_SOF0); /* baseline */
|
295 |
+
emit_word(3 * m_num_components + 2 + 5 + 1);
|
296 |
+
emit_byte(8); /* precision */
|
297 |
+
emit_word(m_image_y);
|
298 |
+
emit_word(m_image_x);
|
299 |
+
emit_byte(m_num_components);
|
300 |
+
for (int i = 0; i < m_num_components; i++)
|
301 |
+
{
|
302 |
+
emit_byte(static_cast<uint8>(i + 1)); /* component ID */
|
303 |
+
emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */
|
304 |
+
emit_byte(i > 0); /* quant. table num */
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
// Emit Huffman table.
|
309 |
+
void jpeg_encoder::emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag)
|
310 |
+
{
|
311 |
+
emit_marker(M_DHT);
|
312 |
+
|
313 |
+
int length = 0;
|
314 |
+
for (int i = 1; i <= 16; i++)
|
315 |
+
length += bits[i];
|
316 |
+
|
317 |
+
emit_word(length + 2 + 1 + 16);
|
318 |
+
emit_byte(static_cast<uint8>(index + (ac_flag << 4)));
|
319 |
+
|
320 |
+
for (int i = 1; i <= 16; i++)
|
321 |
+
emit_byte(bits[i]);
|
322 |
+
|
323 |
+
for (int i = 0; i < length; i++)
|
324 |
+
emit_byte(val[i]);
|
325 |
+
}
|
326 |
+
|
327 |
+
// Emit all Huffman tables.
|
328 |
+
void jpeg_encoder::emit_dhts()
|
329 |
+
{
|
330 |
+
emit_dht(m_huff_bits[0+0], m_huff_val[0+0], 0, false);
|
331 |
+
emit_dht(m_huff_bits[2+0], m_huff_val[2+0], 0, true);
|
332 |
+
if (m_num_components == 3)
|
333 |
+
{
|
334 |
+
emit_dht(m_huff_bits[0+1], m_huff_val[0+1], 1, false);
|
335 |
+
emit_dht(m_huff_bits[2+1], m_huff_val[2+1], 1, true);
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
// emit start of scan
|
340 |
+
void jpeg_encoder::emit_sos()
|
341 |
+
{
|
342 |
+
emit_marker(M_SOS);
|
343 |
+
emit_word(2 * m_num_components + 2 + 1 + 3);
|
344 |
+
emit_byte(m_num_components);
|
345 |
+
for (int i = 0; i < m_num_components; i++)
|
346 |
+
{
|
347 |
+
emit_byte(static_cast<uint8>(i + 1));
|
348 |
+
if (i == 0)
|
349 |
+
emit_byte((0 << 4) + 0);
|
350 |
+
else
|
351 |
+
emit_byte((1 << 4) + 1);
|
352 |
+
}
|
353 |
+
emit_byte(0); /* spectral selection */
|
354 |
+
emit_byte(63);
|
355 |
+
emit_byte(0);
|
356 |
+
}
|
357 |
+
|
358 |
+
// Emit all markers at beginning of image file.
|
359 |
+
void jpeg_encoder::emit_markers()
|
360 |
+
{
|
361 |
+
emit_marker(M_SOI);
|
362 |
+
emit_jfif_app0();
|
363 |
+
emit_dqt();
|
364 |
+
emit_sof();
|
365 |
+
emit_dhts();
|
366 |
+
emit_sos();
|
367 |
+
}
|
368 |
+
|
369 |
+
// Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays.
|
370 |
+
void jpeg_encoder::compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val)
|
371 |
+
{
|
372 |
+
int i, l, last_p, si;
|
373 |
+
uint8 huff_size[257];
|
374 |
+
uint huff_code[257];
|
375 |
+
uint code;
|
376 |
+
|
377 |
+
int p = 0;
|
378 |
+
for (l = 1; l <= 16; l++)
|
379 |
+
for (i = 1; i <= bits[l]; i++)
|
380 |
+
huff_size[p++] = (char)l;
|
381 |
+
|
382 |
+
huff_size[p] = 0; last_p = p; // write sentinel
|
383 |
+
|
384 |
+
code = 0; si = huff_size[0]; p = 0;
|
385 |
+
|
386 |
+
while (huff_size[p])
|
387 |
+
{
|
388 |
+
while (huff_size[p] == si)
|
389 |
+
huff_code[p++] = code++;
|
390 |
+
code <<= 1;
|
391 |
+
si++;
|
392 |
+
}
|
393 |
+
|
394 |
+
memset(codes, 0, sizeof(codes[0])*256);
|
395 |
+
memset(code_sizes, 0, sizeof(code_sizes[0])*256);
|
396 |
+
for (p = 0; p < last_p; p++)
|
397 |
+
{
|
398 |
+
codes[val[p]] = huff_code[p];
|
399 |
+
code_sizes[val[p]] = huff_size[p];
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
// Quantization table generation.
|
404 |
+
void jpeg_encoder::compute_quant_table(int32 *pDst, int16 *pSrc)
|
405 |
+
{
|
406 |
+
int32 q;
|
407 |
+
if (m_params.m_quality < 50)
|
408 |
+
q = 5000 / m_params.m_quality;
|
409 |
+
else
|
410 |
+
q = 200 - m_params.m_quality * 2;
|
411 |
+
for (int i = 0; i < 64; i++)
|
412 |
+
{
|
413 |
+
int32 j = *pSrc++; j = (j * q + 50L) / 100L;
|
414 |
+
*pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255);
|
415 |
+
}
|
416 |
+
}
|
417 |
+
|
418 |
+
// Higher-level methods.
|
419 |
+
void jpeg_encoder::first_pass_init()
|
420 |
+
{
|
421 |
+
m_bit_buffer = 0; m_bits_in = 0;
|
422 |
+
memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0]));
|
423 |
+
m_mcu_y_ofs = 0;
|
424 |
+
m_pass_num = 1;
|
425 |
+
}
|
426 |
+
|
427 |
+
bool jpeg_encoder::second_pass_init()
|
428 |
+
{
|
429 |
+
compute_huffman_table(&m_huff_codes[0+0][0], &m_huff_code_sizes[0+0][0], m_huff_bits[0+0], m_huff_val[0+0]);
|
430 |
+
compute_huffman_table(&m_huff_codes[2+0][0], &m_huff_code_sizes[2+0][0], m_huff_bits[2+0], m_huff_val[2+0]);
|
431 |
+
if (m_num_components > 1)
|
432 |
+
{
|
433 |
+
compute_huffman_table(&m_huff_codes[0+1][0], &m_huff_code_sizes[0+1][0], m_huff_bits[0+1], m_huff_val[0+1]);
|
434 |
+
compute_huffman_table(&m_huff_codes[2+1][0], &m_huff_code_sizes[2+1][0], m_huff_bits[2+1], m_huff_val[2+1]);
|
435 |
+
}
|
436 |
+
first_pass_init();
|
437 |
+
emit_markers();
|
438 |
+
m_pass_num = 2;
|
439 |
+
return true;
|
440 |
+
}
|
441 |
+
|
442 |
+
bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels)
|
443 |
+
{
|
444 |
+
m_num_components = 3;
|
445 |
+
switch (m_params.m_subsampling)
|
446 |
+
{
|
447 |
+
case Y_ONLY:
|
448 |
+
{
|
449 |
+
m_num_components = 1;
|
450 |
+
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
451 |
+
m_mcu_x = 8; m_mcu_y = 8;
|
452 |
+
break;
|
453 |
+
}
|
454 |
+
case H1V1:
|
455 |
+
{
|
456 |
+
m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1;
|
457 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
458 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
459 |
+
m_mcu_x = 8; m_mcu_y = 8;
|
460 |
+
break;
|
461 |
+
}
|
462 |
+
case H2V1:
|
463 |
+
{
|
464 |
+
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1;
|
465 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
466 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
467 |
+
m_mcu_x = 16; m_mcu_y = 8;
|
468 |
+
break;
|
469 |
+
}
|
470 |
+
case H2V2:
|
471 |
+
{
|
472 |
+
m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2;
|
473 |
+
m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1;
|
474 |
+
m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1;
|
475 |
+
m_mcu_x = 16; m_mcu_y = 16;
|
476 |
+
}
|
477 |
+
}
|
478 |
+
|
479 |
+
m_image_x = p_x_res; m_image_y = p_y_res;
|
480 |
+
m_image_bpp = src_channels;
|
481 |
+
m_image_bpl = m_image_x * src_channels;
|
482 |
+
m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1));
|
483 |
+
m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1));
|
484 |
+
m_image_bpl_xlt = m_image_x * m_num_components;
|
485 |
+
m_image_bpl_mcu = m_image_x_mcu * m_num_components;
|
486 |
+
m_mcus_per_row = m_image_x_mcu / m_mcu_x;
|
487 |
+
|
488 |
+
if ((m_mcu_lines[0] = static_cast<uint8*>(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) return false;
|
489 |
+
for (int i = 1; i < m_mcu_y; i++)
|
490 |
+
m_mcu_lines[i] = m_mcu_lines[i-1] + m_image_bpl_mcu;
|
491 |
+
|
492 |
+
compute_quant_table(m_quantization_tables[0], s_std_lum_quant);
|
493 |
+
compute_quant_table(m_quantization_tables[1], m_params.m_no_chroma_discrim_flag ? s_std_lum_quant : s_std_croma_quant);
|
494 |
+
|
495 |
+
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
496 |
+
m_pOut_buf = m_out_buf;
|
497 |
+
|
498 |
+
if (m_params.m_two_pass_flag)
|
499 |
+
{
|
500 |
+
clear_obj(m_huff_count);
|
501 |
+
first_pass_init();
|
502 |
+
}
|
503 |
+
else
|
504 |
+
{
|
505 |
+
memcpy(m_huff_bits[0+0], s_dc_lum_bits, 17); memcpy(m_huff_val [0+0], s_dc_lum_val, DC_LUM_CODES);
|
506 |
+
memcpy(m_huff_bits[2+0], s_ac_lum_bits, 17); memcpy(m_huff_val [2+0], s_ac_lum_val, AC_LUM_CODES);
|
507 |
+
memcpy(m_huff_bits[0+1], s_dc_chroma_bits, 17); memcpy(m_huff_val [0+1], s_dc_chroma_val, DC_CHROMA_CODES);
|
508 |
+
memcpy(m_huff_bits[2+1], s_ac_chroma_bits, 17); memcpy(m_huff_val [2+1], s_ac_chroma_val, AC_CHROMA_CODES);
|
509 |
+
if (!second_pass_init()) return false; // in effect, skip over the first pass
|
510 |
+
}
|
511 |
+
return m_all_stream_writes_succeeded;
|
512 |
+
}
|
513 |
+
|
514 |
+
void jpeg_encoder::load_block_8_8_grey(int x)
|
515 |
+
{
|
516 |
+
uint8 *pSrc;
|
517 |
+
sample_array_t *pDst = m_sample_array;
|
518 |
+
x <<= 3;
|
519 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
520 |
+
{
|
521 |
+
pSrc = m_mcu_lines[i] + x;
|
522 |
+
pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128;
|
523 |
+
pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128;
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
void jpeg_encoder::load_block_8_8(int x, int y, int c)
|
528 |
+
{
|
529 |
+
uint8 *pSrc;
|
530 |
+
sample_array_t *pDst = m_sample_array;
|
531 |
+
x = (x * (8 * 3)) + c;
|
532 |
+
y <<= 3;
|
533 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
534 |
+
{
|
535 |
+
pSrc = m_mcu_lines[y + i] + x;
|
536 |
+
pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128;
|
537 |
+
pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128;
|
538 |
+
}
|
539 |
+
}
|
540 |
+
|
541 |
+
void jpeg_encoder::load_block_16_8(int x, int c)
|
542 |
+
{
|
543 |
+
uint8 *pSrc1, *pSrc2;
|
544 |
+
sample_array_t *pDst = m_sample_array;
|
545 |
+
x = (x * (16 * 3)) + c;
|
546 |
+
int a = 0, b = 2;
|
547 |
+
for (int i = 0; i < 16; i += 2, pDst += 8)
|
548 |
+
{
|
549 |
+
pSrc1 = m_mcu_lines[i + 0] + x;
|
550 |
+
pSrc2 = m_mcu_lines[i + 1] + x;
|
551 |
+
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3] + pSrc2[ 0 * 3] + pSrc2[ 1 * 3] + a) >> 2) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3] + pSrc2[ 2 * 3] + pSrc2[ 3 * 3] + b) >> 2) - 128;
|
552 |
+
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3] + pSrc2[ 4 * 3] + pSrc2[ 5 * 3] + a) >> 2) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3] + pSrc2[ 6 * 3] + pSrc2[ 7 * 3] + b) >> 2) - 128;
|
553 |
+
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3] + pSrc2[ 8 * 3] + pSrc2[ 9 * 3] + a) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + b) >> 2) - 128;
|
554 |
+
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + a) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + b) >> 2) - 128;
|
555 |
+
int temp = a; a = b; b = temp;
|
556 |
+
}
|
557 |
+
}
|
558 |
+
|
559 |
+
void jpeg_encoder::load_block_16_8_8(int x, int c)
|
560 |
+
{
|
561 |
+
uint8 *pSrc1;
|
562 |
+
sample_array_t *pDst = m_sample_array;
|
563 |
+
x = (x * (16 * 3)) + c;
|
564 |
+
for (int i = 0; i < 8; i++, pDst += 8)
|
565 |
+
{
|
566 |
+
pSrc1 = m_mcu_lines[i + 0] + x;
|
567 |
+
pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3]) >> 1) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3]) >> 1) - 128;
|
568 |
+
pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3]) >> 1) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3]) >> 1) - 128;
|
569 |
+
pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3]) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3]) >> 1) - 128;
|
570 |
+
pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3]) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3]) >> 1) - 128;
|
571 |
+
}
|
572 |
+
}
|
573 |
+
|
574 |
+
void jpeg_encoder::load_quantized_coefficients(int component_num)
|
575 |
+
{
|
576 |
+
int32 *q = m_quantization_tables[component_num > 0];
|
577 |
+
int16 *pDst = m_coefficient_array;
|
578 |
+
for (int i = 0; i < 64; i++)
|
579 |
+
{
|
580 |
+
sample_array_t j = m_sample_array[s_zag[i]];
|
581 |
+
if (j < 0)
|
582 |
+
{
|
583 |
+
if ((j = -j + (*q >> 1)) < *q)
|
584 |
+
*pDst++ = 0;
|
585 |
+
else
|
586 |
+
*pDst++ = static_cast<int16>(-(j / *q));
|
587 |
+
}
|
588 |
+
else
|
589 |
+
{
|
590 |
+
if ((j = j + (*q >> 1)) < *q)
|
591 |
+
*pDst++ = 0;
|
592 |
+
else
|
593 |
+
*pDst++ = static_cast<int16>((j / *q));
|
594 |
+
}
|
595 |
+
q++;
|
596 |
+
}
|
597 |
+
}
|
598 |
+
|
599 |
+
void jpeg_encoder::flush_output_buffer()
|
600 |
+
{
|
601 |
+
if (m_out_buf_left != JPGE_OUT_BUF_SIZE)
|
602 |
+
m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left);
|
603 |
+
m_pOut_buf = m_out_buf;
|
604 |
+
m_out_buf_left = JPGE_OUT_BUF_SIZE;
|
605 |
+
}
|
606 |
+
|
607 |
+
void jpeg_encoder::put_bits(uint bits, uint len)
|
608 |
+
{
|
609 |
+
m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len)));
|
610 |
+
while (m_bits_in >= 8)
|
611 |
+
{
|
612 |
+
uint8 c;
|
613 |
+
#define JPGE_PUT_BYTE(c) { *m_pOut_buf++ = (c); if (--m_out_buf_left == 0) flush_output_buffer(); }
|
614 |
+
JPGE_PUT_BYTE(c = (uint8)((m_bit_buffer >> 16) & 0xFF));
|
615 |
+
if (c == 0xFF) JPGE_PUT_BYTE(0);
|
616 |
+
m_bit_buffer <<= 8;
|
617 |
+
m_bits_in -= 8;
|
618 |
+
}
|
619 |
+
}
|
620 |
+
|
621 |
+
void jpeg_encoder::code_coefficients_pass_one(int component_num)
|
622 |
+
{
|
623 |
+
if (component_num >= 3) return; // just to shut up static analysis
|
624 |
+
int i, run_len, nbits, temp1;
|
625 |
+
int16 *src = m_coefficient_array;
|
626 |
+
uint32 *dc_count = component_num ? m_huff_count[0 + 1] : m_huff_count[0 + 0], *ac_count = component_num ? m_huff_count[2 + 1] : m_huff_count[2 + 0];
|
627 |
+
|
628 |
+
temp1 = src[0] - m_last_dc_val[component_num];
|
629 |
+
m_last_dc_val[component_num] = src[0];
|
630 |
+
if (temp1 < 0) temp1 = -temp1;
|
631 |
+
|
632 |
+
nbits = 0;
|
633 |
+
while (temp1)
|
634 |
+
{
|
635 |
+
nbits++; temp1 >>= 1;
|
636 |
+
}
|
637 |
+
|
638 |
+
dc_count[nbits]++;
|
639 |
+
for (run_len = 0, i = 1; i < 64; i++)
|
640 |
+
{
|
641 |
+
if ((temp1 = m_coefficient_array[i]) == 0)
|
642 |
+
run_len++;
|
643 |
+
else
|
644 |
+
{
|
645 |
+
while (run_len >= 16)
|
646 |
+
{
|
647 |
+
ac_count[0xF0]++;
|
648 |
+
run_len -= 16;
|
649 |
+
}
|
650 |
+
if (temp1 < 0) temp1 = -temp1;
|
651 |
+
nbits = 1;
|
652 |
+
while (temp1 >>= 1) nbits++;
|
653 |
+
ac_count[(run_len << 4) + nbits]++;
|
654 |
+
run_len = 0;
|
655 |
+
}
|
656 |
+
}
|
657 |
+
if (run_len) ac_count[0]++;
|
658 |
+
}
|
659 |
+
|
660 |
+
void jpeg_encoder::code_coefficients_pass_two(int component_num)
|
661 |
+
{
|
662 |
+
int i, j, run_len, nbits, temp1, temp2;
|
663 |
+
int16 *pSrc = m_coefficient_array;
|
664 |
+
uint *codes[2];
|
665 |
+
uint8 *code_sizes[2];
|
666 |
+
|
667 |
+
if (component_num == 0)
|
668 |
+
{
|
669 |
+
codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0];
|
670 |
+
code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0];
|
671 |
+
}
|
672 |
+
else
|
673 |
+
{
|
674 |
+
codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1];
|
675 |
+
code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1];
|
676 |
+
}
|
677 |
+
|
678 |
+
temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num];
|
679 |
+
m_last_dc_val[component_num] = pSrc[0];
|
680 |
+
|
681 |
+
if (temp1 < 0)
|
682 |
+
{
|
683 |
+
temp1 = -temp1; temp2--;
|
684 |
+
}
|
685 |
+
|
686 |
+
nbits = 0;
|
687 |
+
while (temp1)
|
688 |
+
{
|
689 |
+
nbits++; temp1 >>= 1;
|
690 |
+
}
|
691 |
+
|
692 |
+
put_bits(codes[0][nbits], code_sizes[0][nbits]);
|
693 |
+
if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
694 |
+
|
695 |
+
for (run_len = 0, i = 1; i < 64; i++)
|
696 |
+
{
|
697 |
+
if ((temp1 = m_coefficient_array[i]) == 0)
|
698 |
+
run_len++;
|
699 |
+
else
|
700 |
+
{
|
701 |
+
while (run_len >= 16)
|
702 |
+
{
|
703 |
+
put_bits(codes[1][0xF0], code_sizes[1][0xF0]);
|
704 |
+
run_len -= 16;
|
705 |
+
}
|
706 |
+
if ((temp2 = temp1) < 0)
|
707 |
+
{
|
708 |
+
temp1 = -temp1;
|
709 |
+
temp2--;
|
710 |
+
}
|
711 |
+
nbits = 1;
|
712 |
+
while (temp1 >>= 1)
|
713 |
+
nbits++;
|
714 |
+
j = (run_len << 4) + nbits;
|
715 |
+
put_bits(codes[1][j], code_sizes[1][j]);
|
716 |
+
put_bits(temp2 & ((1 << nbits) - 1), nbits);
|
717 |
+
run_len = 0;
|
718 |
+
}
|
719 |
+
}
|
720 |
+
if (run_len)
|
721 |
+
put_bits(codes[1][0], code_sizes[1][0]);
|
722 |
+
}
|
723 |
+
|
724 |
+
void jpeg_encoder::code_block(int component_num)
|
725 |
+
{
|
726 |
+
DCT2D(m_sample_array);
|
727 |
+
load_quantized_coefficients(component_num);
|
728 |
+
if (m_pass_num == 1)
|
729 |
+
code_coefficients_pass_one(component_num);
|
730 |
+
else
|
731 |
+
code_coefficients_pass_two(component_num);
|
732 |
+
}
|
733 |
+
|
734 |
+
void jpeg_encoder::process_mcu_row()
|
735 |
+
{
|
736 |
+
if (m_num_components == 1)
|
737 |
+
{
|
738 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
739 |
+
{
|
740 |
+
load_block_8_8_grey(i); code_block(0);
|
741 |
+
}
|
742 |
+
}
|
743 |
+
else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
|
744 |
+
{
|
745 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
746 |
+
{
|
747 |
+
load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2);
|
748 |
+
}
|
749 |
+
}
|
750 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
|
751 |
+
{
|
752 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
753 |
+
{
|
754 |
+
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
755 |
+
load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2);
|
756 |
+
}
|
757 |
+
}
|
758 |
+
else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
|
759 |
+
{
|
760 |
+
for (int i = 0; i < m_mcus_per_row; i++)
|
761 |
+
{
|
762 |
+
load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0);
|
763 |
+
load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0);
|
764 |
+
load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2);
|
765 |
+
}
|
766 |
+
}
|
767 |
+
}
|
768 |
+
|
769 |
+
bool jpeg_encoder::terminate_pass_one()
|
770 |
+
{
|
771 |
+
optimize_huffman_table(0+0, DC_LUM_CODES); optimize_huffman_table(2+0, AC_LUM_CODES);
|
772 |
+
if (m_num_components > 1)
|
773 |
+
{
|
774 |
+
optimize_huffman_table(0+1, DC_CHROMA_CODES); optimize_huffman_table(2+1, AC_CHROMA_CODES);
|
775 |
+
}
|
776 |
+
return second_pass_init();
|
777 |
+
}
|
778 |
+
|
779 |
+
bool jpeg_encoder::terminate_pass_two()
|
780 |
+
{
|
781 |
+
put_bits(0x7F, 7);
|
782 |
+
flush_output_buffer();
|
783 |
+
emit_marker(M_EOI);
|
784 |
+
m_pass_num++; // purposely bump up m_pass_num, for debugging
|
785 |
+
return true;
|
786 |
+
}
|
787 |
+
|
788 |
+
bool jpeg_encoder::process_end_of_image()
|
789 |
+
{
|
790 |
+
if (m_mcu_y_ofs)
|
791 |
+
{
|
792 |
+
if (m_mcu_y_ofs < 16) // check here just to shut up static analysis
|
793 |
+
{
|
794 |
+
for (int i = m_mcu_y_ofs; i < m_mcu_y; i++)
|
795 |
+
memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu);
|
796 |
+
}
|
797 |
+
|
798 |
+
process_mcu_row();
|
799 |
+
}
|
800 |
+
|
801 |
+
if (m_pass_num == 1)
|
802 |
+
return terminate_pass_one();
|
803 |
+
else
|
804 |
+
return terminate_pass_two();
|
805 |
+
}
|
806 |
+
|
807 |
+
void jpeg_encoder::load_mcu(const void *pSrc)
|
808 |
+
{
|
809 |
+
const uint8* Psrc = reinterpret_cast<const uint8*>(pSrc);
|
810 |
+
|
811 |
+
uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst
|
812 |
+
|
813 |
+
if (m_num_components == 1)
|
814 |
+
{
|
815 |
+
if (m_image_bpp == 4)
|
816 |
+
RGBA_to_Y(pDst, Psrc, m_image_x);
|
817 |
+
else if (m_image_bpp == 3)
|
818 |
+
RGB_to_Y(pDst, Psrc, m_image_x);
|
819 |
+
else
|
820 |
+
memcpy(pDst, Psrc, m_image_x);
|
821 |
+
}
|
822 |
+
else
|
823 |
+
{
|
824 |
+
if (m_image_bpp == 4)
|
825 |
+
RGBA_to_YCC(pDst, Psrc, m_image_x);
|
826 |
+
else if (m_image_bpp == 3)
|
827 |
+
RGB_to_YCC(pDst, Psrc, m_image_x);
|
828 |
+
else
|
829 |
+
Y_to_YCC(pDst, Psrc, m_image_x);
|
830 |
+
}
|
831 |
+
|
832 |
+
// Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16
|
833 |
+
if (m_num_components == 1)
|
834 |
+
memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x);
|
835 |
+
else
|
836 |
+
{
|
837 |
+
const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2];
|
838 |
+
uint8 *q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt;
|
839 |
+
for (int i = m_image_x; i < m_image_x_mcu; i++)
|
840 |
+
{
|
841 |
+
*q++ = y; *q++ = cb; *q++ = cr;
|
842 |
+
}
|
843 |
+
}
|
844 |
+
|
845 |
+
if (++m_mcu_y_ofs == m_mcu_y)
|
846 |
+
{
|
847 |
+
process_mcu_row();
|
848 |
+
m_mcu_y_ofs = 0;
|
849 |
+
}
|
850 |
+
}
|
851 |
+
|
852 |
+
void jpeg_encoder::clear()
|
853 |
+
{
|
854 |
+
m_mcu_lines[0] = NULL;
|
855 |
+
m_pass_num = 0;
|
856 |
+
m_all_stream_writes_succeeded = true;
|
857 |
+
}
|
858 |
+
|
859 |
+
jpeg_encoder::jpeg_encoder()
|
860 |
+
{
|
861 |
+
clear();
|
862 |
+
}
|
863 |
+
|
864 |
+
jpeg_encoder::~jpeg_encoder()
|
865 |
+
{
|
866 |
+
deinit();
|
867 |
+
}
|
868 |
+
|
869 |
+
bool jpeg_encoder::init(output_stream *pStream, int64_t width, int64_t height, int64_t src_channels, const params &comp_params)
|
870 |
+
{
|
871 |
+
deinit();
|
872 |
+
if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check_valid())) return false;
|
873 |
+
m_pStream = pStream;
|
874 |
+
m_params = comp_params;
|
875 |
+
return jpg_open(width, height, src_channels);
|
876 |
+
}
|
877 |
+
|
878 |
+
void jpeg_encoder::deinit()
|
879 |
+
{
|
880 |
+
jpge_free(m_mcu_lines[0]);
|
881 |
+
clear();
|
882 |
+
}
|
883 |
+
|
884 |
+
bool jpeg_encoder::process_scanline(const void* pScanline)
|
885 |
+
{
|
886 |
+
if ((m_pass_num < 1) || (m_pass_num > 2)) return false;
|
887 |
+
if (m_all_stream_writes_succeeded)
|
888 |
+
{
|
889 |
+
if (!pScanline)
|
890 |
+
{
|
891 |
+
if (!process_end_of_image()) return false;
|
892 |
+
}
|
893 |
+
else
|
894 |
+
{
|
895 |
+
load_mcu(pScanline);
|
896 |
+
}
|
897 |
+
}
|
898 |
+
return m_all_stream_writes_succeeded;
|
899 |
+
}
|
900 |
+
|
901 |
+
// Higher level wrappers/examples (optional).
|
902 |
+
#include <stdio.h>
|
903 |
+
|
904 |
+
class cfile_stream : public output_stream
|
905 |
+
{
|
906 |
+
cfile_stream(const cfile_stream &);
|
907 |
+
cfile_stream &operator= (const cfile_stream &);
|
908 |
+
|
909 |
+
FILE* m_pFile;
|
910 |
+
bool m_bStatus;
|
911 |
+
|
912 |
+
public:
|
913 |
+
cfile_stream() : m_pFile(NULL), m_bStatus(false) { }
|
914 |
+
|
915 |
+
virtual ~cfile_stream()
|
916 |
+
{
|
917 |
+
close();
|
918 |
+
}
|
919 |
+
|
920 |
+
bool open(const char *pFilename)
|
921 |
+
{
|
922 |
+
close();
|
923 |
+
#if defined(_MSC_VER)
|
924 |
+
if (fopen_s(&m_pFile, pFilename, "wb") != 0)
|
925 |
+
{
|
926 |
+
return false;
|
927 |
+
}
|
928 |
+
#else
|
929 |
+
m_pFile = fopen(pFilename, "wb");
|
930 |
+
#endif
|
931 |
+
m_bStatus = (m_pFile != NULL);
|
932 |
+
return m_bStatus;
|
933 |
+
}
|
934 |
+
|
935 |
+
bool close()
|
936 |
+
{
|
937 |
+
if (m_pFile)
|
938 |
+
{
|
939 |
+
if (fclose(m_pFile) == EOF)
|
940 |
+
{
|
941 |
+
m_bStatus = false;
|
942 |
+
}
|
943 |
+
m_pFile = NULL;
|
944 |
+
}
|
945 |
+
return m_bStatus;
|
946 |
+
}
|
947 |
+
|
948 |
+
virtual bool put_buf(const void* pBuf, int64_t len)
|
949 |
+
{
|
950 |
+
m_bStatus = m_bStatus && (fwrite(pBuf, len, 1, m_pFile) == 1);
|
951 |
+
return m_bStatus;
|
952 |
+
}
|
953 |
+
|
954 |
+
uint get_size() const
|
955 |
+
{
|
956 |
+
return m_pFile ? ftell(m_pFile) : 0;
|
957 |
+
}
|
958 |
+
};
|
959 |
+
|
960 |
+
// Writes JPEG image to file.
|
961 |
+
bool compress_image_to_jpeg_file(const char *pFilename, int64_t width, int64_t height, int64_t num_channels, const uint8 *pImage_data, const params &comp_params)
|
962 |
+
{
|
963 |
+
cfile_stream dst_stream;
|
964 |
+
if (!dst_stream.open(pFilename))
|
965 |
+
return false;
|
966 |
+
|
967 |
+
jpge::jpeg_encoder dst_image;
|
968 |
+
if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params))
|
969 |
+
return false;
|
970 |
+
|
971 |
+
for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++)
|
972 |
+
{
|
973 |
+
for (int64_t i = 0; i < height; i++)
|
974 |
+
{
|
975 |
+
// i, width, and num_channels are all 64bit
|
976 |
+
const uint8* pBuf = pImage_data + i * width * num_channels;
|
977 |
+
if (!dst_image.process_scanline(pBuf))
|
978 |
+
return false;
|
979 |
+
}
|
980 |
+
if (!dst_image.process_scanline(NULL))
|
981 |
+
return false;
|
982 |
+
}
|
983 |
+
|
984 |
+
dst_image.deinit();
|
985 |
+
|
986 |
+
return dst_stream.close();
|
987 |
+
}
|
988 |
+
|
989 |
+
class memory_stream : public output_stream
|
990 |
+
{
|
991 |
+
memory_stream(const memory_stream &);
|
992 |
+
memory_stream &operator= (const memory_stream &);
|
993 |
+
|
994 |
+
uint8 *m_pBuf;
|
995 |
+
uint64_t m_buf_size, m_buf_ofs;
|
996 |
+
|
997 |
+
public:
|
998 |
+
memory_stream(void *pBuf, uint64_t buf_size) : m_pBuf(static_cast<uint8*>(pBuf)), m_buf_size(buf_size), m_buf_ofs(0) { }
|
999 |
+
|
1000 |
+
virtual ~memory_stream() { }
|
1001 |
+
|
1002 |
+
virtual bool put_buf(const void* pBuf, int64_t len)
|
1003 |
+
{
|
1004 |
+
uint64_t buf_remaining = m_buf_size - m_buf_ofs;
|
1005 |
+
if ((uint64_t)len > buf_remaining)
|
1006 |
+
return false;
|
1007 |
+
memcpy(m_pBuf + m_buf_ofs, pBuf, len);
|
1008 |
+
m_buf_ofs += len;
|
1009 |
+
return true;
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
uint64_t get_size() const
|
1013 |
+
{
|
1014 |
+
return m_buf_ofs;
|
1015 |
+
}
|
1016 |
+
};
|
1017 |
+
|
1018 |
+
bool compress_image_to_jpeg_file_in_memory(void *pDstBuf, int64_t &buf_size, int64_t width, int64_t height, int64_t num_channels, const uint8 *pImage_data, const params &comp_params)
|
1019 |
+
{
|
1020 |
+
if ((!pDstBuf) || (!buf_size))
|
1021 |
+
return false;
|
1022 |
+
|
1023 |
+
memory_stream dst_stream(pDstBuf, buf_size);
|
1024 |
+
|
1025 |
+
buf_size = 0;
|
1026 |
+
|
1027 |
+
jpge::jpeg_encoder dst_image;
|
1028 |
+
if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params))
|
1029 |
+
return false;
|
1030 |
+
|
1031 |
+
for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++)
|
1032 |
+
{
|
1033 |
+
for (int64_t i = 0; i < height; i++)
|
1034 |
+
{
|
1035 |
+
const uint8* pScanline = pImage_data + i * width * num_channels;
|
1036 |
+
if (!dst_image.process_scanline(pScanline))
|
1037 |
+
return false;
|
1038 |
+
}
|
1039 |
+
if (!dst_image.process_scanline(NULL))
|
1040 |
+
return false;
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
dst_image.deinit();
|
1044 |
+
|
1045 |
+
buf_size = dst_stream.get_size();
|
1046 |
+
return true;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
} // namespace jpge
|
crazy_functions/test_project/cpp/longcode/prod_cons.h
ADDED
@@ -0,0 +1,433 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#include <atomic>
|
4 |
+
#include <utility>
|
5 |
+
#include <cstring>
|
6 |
+
#include <type_traits>
|
7 |
+
#include <cstdint>
|
8 |
+
|
9 |
+
#include "libipc/def.h"
|
10 |
+
|
11 |
+
#include "libipc/platform/detail.h"
|
12 |
+
#include "libipc/circ/elem_def.h"
|
13 |
+
#include "libipc/utility/log.h"
|
14 |
+
#include "libipc/utility/utility.h"
|
15 |
+
|
16 |
+
namespace ipc {
|
17 |
+
|
18 |
+
////////////////////////////////////////////////////////////////
|
19 |
+
/// producer-consumer implementation
|
20 |
+
////////////////////////////////////////////////////////////////
|
21 |
+
|
22 |
+
template <typename Flag>
|
23 |
+
struct prod_cons_impl;
|
24 |
+
|
25 |
+
template <>
|
26 |
+
struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
27 |
+
|
28 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
29 |
+
struct elem_t {
|
30 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
31 |
+
};
|
32 |
+
|
33 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
|
34 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
35 |
+
|
36 |
+
constexpr circ::u2_t cursor() const noexcept {
|
37 |
+
return 0;
|
38 |
+
}
|
39 |
+
|
40 |
+
template <typename W, typename F, typename E>
|
41 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
42 |
+
auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
|
43 |
+
if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
|
44 |
+
return false; // full
|
45 |
+
}
|
46 |
+
std::forward<F>(f)(&(elems[cur_wt].data_));
|
47 |
+
wt_.fetch_add(1, std::memory_order_release);
|
48 |
+
return true;
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
|
53 |
+
* So we could just disconnect all connections of receiver, and return false.
|
54 |
+
*/
|
55 |
+
template <typename W, typename F, typename E>
|
56 |
+
bool force_push(W* wrapper, F&&, E*) {
|
57 |
+
wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
template <typename W, typename F, typename R, typename E>
|
62 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
|
63 |
+
auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
|
64 |
+
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
|
65 |
+
return false; // empty
|
66 |
+
}
|
67 |
+
std::forward<F>(f)(&(elems[cur_rd].data_));
|
68 |
+
std::forward<R>(out)(true);
|
69 |
+
rd_.fetch_add(1, std::memory_order_release);
|
70 |
+
return true;
|
71 |
+
}
|
72 |
+
};
|
73 |
+
|
74 |
+
template <>
|
75 |
+
struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
|
76 |
+
: prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
77 |
+
|
78 |
+
template <typename W, typename F, typename E>
|
79 |
+
bool force_push(W* wrapper, F&&, E*) {
|
80 |
+
wrapper->elems()->disconnect_receiver(1);
|
81 |
+
return false;
|
82 |
+
}
|
83 |
+
|
84 |
+
template <typename W, typename F, typename R,
|
85 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
86 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
87 |
+
byte_t buff[DS];
|
88 |
+
for (unsigned k = 0;;) {
|
89 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
90 |
+
if (circ::index_of(cur_rd) ==
|
91 |
+
circ::index_of(wt_.load(std::memory_order_acquire))) {
|
92 |
+
return false; // empty
|
93 |
+
}
|
94 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
95 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
96 |
+
std::forward<F>(f)(buff);
|
97 |
+
std::forward<R>(out)(true);
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
ipc::yield(k);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
};
|
104 |
+
|
105 |
+
template <>
|
106 |
+
struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
|
107 |
+
: prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
|
108 |
+
|
109 |
+
using flag_t = std::uint64_t;
|
110 |
+
|
111 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
112 |
+
struct elem_t {
|
113 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
114 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
115 |
+
};
|
116 |
+
|
117 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
118 |
+
|
119 |
+
template <typename W, typename F, typename E>
|
120 |
+
bool push(W* /*wrapper*/, F&& f, E* elems) {
|
121 |
+
circ::u2_t cur_ct, nxt_ct;
|
122 |
+
for (unsigned k = 0;;) {
|
123 |
+
cur_ct = ct_.load(std::memory_order_relaxed);
|
124 |
+
if (circ::index_of(nxt_ct = cur_ct + 1) ==
|
125 |
+
circ::index_of(rd_.load(std::memory_order_acquire))) {
|
126 |
+
return false; // full
|
127 |
+
}
|
128 |
+
if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
|
129 |
+
break;
|
130 |
+
}
|
131 |
+
ipc::yield(k);
|
132 |
+
}
|
133 |
+
auto* el = elems + circ::index_of(cur_ct);
|
134 |
+
std::forward<F>(f)(&(el->data_));
|
135 |
+
// set flag & try update wt
|
136 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
137 |
+
while (1) {
|
138 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
139 |
+
if (cur_ct != wt_.load(std::memory_order_relaxed)) {
|
140 |
+
return true;
|
141 |
+
}
|
142 |
+
if ((~cac_ct) != cur_ct) {
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
|
146 |
+
return true;
|
147 |
+
}
|
148 |
+
wt_.store(nxt_ct, std::memory_order_release);
|
149 |
+
cur_ct = nxt_ct;
|
150 |
+
nxt_ct = cur_ct + 1;
|
151 |
+
el = elems + circ::index_of(cur_ct);
|
152 |
+
}
|
153 |
+
return true;
|
154 |
+
}
|
155 |
+
|
156 |
+
template <typename W, typename F, typename E>
|
157 |
+
bool force_push(W* wrapper, F&&, E*) {
|
158 |
+
wrapper->elems()->disconnect_receiver(1);
|
159 |
+
return false;
|
160 |
+
}
|
161 |
+
|
162 |
+
template <typename W, typename F, typename R,
|
163 |
+
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
164 |
+
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
|
165 |
+
byte_t buff[DS];
|
166 |
+
for (unsigned k = 0;;) {
|
167 |
+
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
168 |
+
auto cur_wt = wt_.load(std::memory_order_acquire);
|
169 |
+
auto id_rd = circ::index_of(cur_rd);
|
170 |
+
auto id_wt = circ::index_of(cur_wt);
|
171 |
+
if (id_rd == id_wt) {
|
172 |
+
auto* el = elems + id_wt;
|
173 |
+
auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
|
174 |
+
if ((~cac_ct) != cur_wt) {
|
175 |
+
return false; // empty
|
176 |
+
}
|
177 |
+
if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
|
178 |
+
wt_.store(cur_wt + 1, std::memory_order_release);
|
179 |
+
}
|
180 |
+
k = 0;
|
181 |
+
}
|
182 |
+
else {
|
183 |
+
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
|
184 |
+
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
185 |
+
std::forward<F>(f)(buff);
|
186 |
+
std::forward<R>(out)(true);
|
187 |
+
return true;
|
188 |
+
}
|
189 |
+
ipc::yield(k);
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
};
|
194 |
+
|
195 |
+
template <>
|
196 |
+
struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
197 |
+
|
198 |
+
using rc_t = std::uint64_t;
|
199 |
+
|
200 |
+
enum : rc_t {
|
201 |
+
ep_mask = 0x00000000ffffffffull,
|
202 |
+
ep_incr = 0x0000000100000000ull
|
203 |
+
};
|
204 |
+
|
205 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
206 |
+
struct elem_t {
|
207 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
208 |
+
std::atomic<rc_t> rc_ { 0 }; // read-counter
|
209 |
+
};
|
210 |
+
|
211 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
|
212 |
+
alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
|
213 |
+
|
214 |
+
circ::u2_t cursor() const noexcept {
|
215 |
+
return wt_.load(std::memory_order_acquire);
|
216 |
+
}
|
217 |
+
|
218 |
+
template <typename W, typename F, typename E>
|
219 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
220 |
+
E* el;
|
221 |
+
for (unsigned k = 0;;) {
|
222 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
223 |
+
if (cc == 0) return false; // no reader
|
224 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
225 |
+
// check all consumers have finished reading this element
|
226 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
227 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
228 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
|
229 |
+
return false; // has not finished yet
|
230 |
+
}
|
231 |
+
// consider rem_cc to be 0 here
|
232 |
+
if (el->rc_.compare_exchange_weak(
|
233 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
234 |
+
break;
|
235 |
+
}
|
236 |
+
ipc::yield(k);
|
237 |
+
}
|
238 |
+
std::forward<F>(f)(&(el->data_));
|
239 |
+
wt_.fetch_add(1, std::memory_order_release);
|
240 |
+
return true;
|
241 |
+
}
|
242 |
+
|
243 |
+
template <typename W, typename F, typename E>
|
244 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
245 |
+
E* el;
|
246 |
+
epoch_ += ep_incr;
|
247 |
+
for (unsigned k = 0;;) {
|
248 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
249 |
+
if (cc == 0) return false; // no reader
|
250 |
+
el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
|
251 |
+
// check all consumers have finished reading this element
|
252 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
253 |
+
circ::cc_t rem_cc = cur_rc & ep_mask;
|
254 |
+
if (cc & rem_cc) {
|
255 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
256 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
257 |
+
if (cc == 0) return false; // no reader
|
258 |
+
}
|
259 |
+
// just compare & exchange
|
260 |
+
if (el->rc_.compare_exchange_weak(
|
261 |
+
cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
|
262 |
+
break;
|
263 |
+
}
|
264 |
+
ipc::yield(k);
|
265 |
+
}
|
266 |
+
std::forward<F>(f)(&(el->data_));
|
267 |
+
wt_.fetch_add(1, std::memory_order_release);
|
268 |
+
return true;
|
269 |
+
}
|
270 |
+
|
271 |
+
template <typename W, typename F, typename R, typename E>
|
272 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
|
273 |
+
if (cur == cursor()) return false; // acquire
|
274 |
+
auto* el = elems + circ::index_of(cur++);
|
275 |
+
std::forward<F>(f)(&(el->data_));
|
276 |
+
for (unsigned k = 0;;) {
|
277 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
278 |
+
if ((cur_rc & ep_mask) == 0) {
|
279 |
+
std::forward<R>(out)(true);
|
280 |
+
return true;
|
281 |
+
}
|
282 |
+
auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
|
283 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
284 |
+
std::forward<R>(out)((nxt_rc & ep_mask) == 0);
|
285 |
+
return true;
|
286 |
+
}
|
287 |
+
ipc::yield(k);
|
288 |
+
}
|
289 |
+
}
|
290 |
+
};
|
291 |
+
|
292 |
+
template <>
|
293 |
+
struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
|
294 |
+
|
295 |
+
using rc_t = std::uint64_t;
|
296 |
+
using flag_t = std::uint64_t;
|
297 |
+
|
298 |
+
enum : rc_t {
|
299 |
+
rc_mask = 0x00000000ffffffffull,
|
300 |
+
ep_mask = 0x00ffffffffffffffull,
|
301 |
+
ep_incr = 0x0100000000000000ull,
|
302 |
+
ic_mask = 0xff000000ffffffffull,
|
303 |
+
ic_incr = 0x0000000100000000ull
|
304 |
+
};
|
305 |
+
|
306 |
+
template <std::size_t DataSize, std::size_t AlignSize>
|
307 |
+
struct elem_t {
|
308 |
+
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
309 |
+
std::atomic<rc_t > rc_ { 0 }; // read-counter
|
310 |
+
std::atomic<flag_t> f_ct_ { 0 }; // commit flag
|
311 |
+
};
|
312 |
+
|
313 |
+
alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
|
314 |
+
alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
|
315 |
+
|
316 |
+
circ::u2_t cursor() const noexcept {
|
317 |
+
return ct_.load(std::memory_order_acquire);
|
318 |
+
}
|
319 |
+
|
320 |
+
constexpr static rc_t inc_rc(rc_t rc) noexcept {
|
321 |
+
return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
|
322 |
+
}
|
323 |
+
|
324 |
+
constexpr static rc_t inc_mask(rc_t rc) noexcept {
|
325 |
+
return inc_rc(rc) & ~rc_mask;
|
326 |
+
}
|
327 |
+
|
328 |
+
template <typename W, typename F, typename E>
|
329 |
+
bool push(W* wrapper, F&& f, E* elems) {
|
330 |
+
E* el;
|
331 |
+
circ::u2_t cur_ct;
|
332 |
+
rc_t epoch = epoch_.load(std::memory_order_acquire);
|
333 |
+
for (unsigned k = 0;;) {
|
334 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
335 |
+
if (cc == 0) return false; // no reader
|
336 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
337 |
+
// check all consumers have finished reading this element
|
338 |
+
auto cur_rc = el->rc_.load(std::memory_order_relaxed);
|
339 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
340 |
+
if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
|
341 |
+
return false; // has not finished yet
|
342 |
+
}
|
343 |
+
else if (!rem_cc) {
|
344 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
345 |
+
if ((cur_fl != cur_ct) && cur_fl) {
|
346 |
+
return false; // full
|
347 |
+
}
|
348 |
+
}
|
349 |
+
// consider rem_cc to be 0 here
|
350 |
+
if (el->rc_.compare_exchange_weak(
|
351 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
|
352 |
+
epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
|
353 |
+
break;
|
354 |
+
}
|
355 |
+
ipc::yield(k);
|
356 |
+
}
|
357 |
+
// only one thread/process would touch here at one time
|
358 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
359 |
+
std::forward<F>(f)(&(el->data_));
|
360 |
+
// set flag & try update wt
|
361 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
362 |
+
return true;
|
363 |
+
}
|
364 |
+
|
365 |
+
template <typename W, typename F, typename E>
|
366 |
+
bool force_push(W* wrapper, F&& f, E* elems) {
|
367 |
+
E* el;
|
368 |
+
circ::u2_t cur_ct;
|
369 |
+
rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
370 |
+
for (unsigned k = 0;;) {
|
371 |
+
circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
|
372 |
+
if (cc == 0) return false; // no reader
|
373 |
+
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
374 |
+
// check all consumers have finished reading this element
|
375 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
376 |
+
circ::cc_t rem_cc = cur_rc & rc_mask;
|
377 |
+
if (cc & rem_cc) {
|
378 |
+
ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
|
379 |
+
cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
|
380 |
+
if (cc == 0) return false; // no reader
|
381 |
+
}
|
382 |
+
// just compare & exchange
|
383 |
+
if (el->rc_.compare_exchange_weak(
|
384 |
+
cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
|
385 |
+
if (epoch == epoch_.load(std::memory_order_acquire)) {
|
386 |
+
break;
|
387 |
+
}
|
388 |
+
else if (push(wrapper, std::forward<F>(f), elems)) {
|
389 |
+
return true;
|
390 |
+
}
|
391 |
+
epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
|
392 |
+
}
|
393 |
+
ipc::yield(k);
|
394 |
+
}
|
395 |
+
// only one thread/process would touch here at one time
|
396 |
+
ct_.store(cur_ct + 1, std::memory_order_release);
|
397 |
+
std::forward<F>(f)(&(el->data_));
|
398 |
+
// set flag & try update wt
|
399 |
+
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
400 |
+
return true;
|
401 |
+
}
|
402 |
+
|
403 |
+
template <typename W, typename F, typename R, typename E, std::size_t N>
|
404 |
+
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
|
405 |
+
auto* el = elems + circ::index_of(cur);
|
406 |
+
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
407 |
+
if (cur_fl != ~static_cast<flag_t>(cur)) {
|
408 |
+
return false; // empty
|
409 |
+
}
|
410 |
+
++cur;
|
411 |
+
std::forward<F>(f)(&(el->data_));
|
412 |
+
for (unsigned k = 0;;) {
|
413 |
+
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
414 |
+
if ((cur_rc & rc_mask) == 0) {
|
415 |
+
std::forward<R>(out)(true);
|
416 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
417 |
+
return true;
|
418 |
+
}
|
419 |
+
auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
|
420 |
+
bool last_one = false;
|
421 |
+
if ((last_one = (nxt_rc & rc_mask) == 0)) {
|
422 |
+
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
423 |
+
}
|
424 |
+
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
425 |
+
std::forward<R>(out)(last_one);
|
426 |
+
return true;
|
427 |
+
}
|
428 |
+
ipc::yield(k);
|
429 |
+
}
|
430 |
+
}
|
431 |
+
};
|
432 |
+
|
433 |
+
} // namespace ipc
|
crazy_functions/总结word文档.py
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from predict import predict_no_ui
|
2 |
+
from toolbox import CatchException, report_execption, write_results_to_file, predict_no_ui_but_counting_down
|
3 |
+
fast_debug = False
|
4 |
+
|
5 |
+
|
6 |
+
def 解析docx(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
|
7 |
+
import time, os
|
8 |
+
# pip install python-docx 用于docx格式,跨平台
|
9 |
+
# pip install pywin32 用于doc格式,仅支持Win平台
|
10 |
+
|
11 |
+
print('begin analysis on:', file_manifest)
|
12 |
+
for index, fp in enumerate(file_manifest):
|
13 |
+
if fp.split(".")[-1] == "docx":
|
14 |
+
from docx import Document
|
15 |
+
doc = Document(fp)
|
16 |
+
file_content = "\n".join([para.text for para in doc.paragraphs])
|
17 |
+
else:
|
18 |
+
import win32com.client
|
19 |
+
word = win32com.client.Dispatch("Word.Application")
|
20 |
+
word.visible = False
|
21 |
+
# 打开文件
|
22 |
+
print('fp', os.getcwd())
|
23 |
+
doc = word.Documents.Open(os.getcwd() + '/' + fp)
|
24 |
+
# file_content = doc.Content.Text
|
25 |
+
doc = word.ActiveDocument
|
26 |
+
file_content = doc.Range().Text
|
27 |
+
doc.Close()
|
28 |
+
word.Quit()
|
29 |
+
|
30 |
+
print(file_content)
|
31 |
+
|
32 |
+
prefix = "接下来请你逐文件分析下面的论文文件," if index == 0 else ""
|
33 |
+
# private_upload里面的文件名在解压zip后容易出现乱码(rar和7z格式正常),故可以只分析文章内容,不输入文件名
|
34 |
+
i_say = prefix + f'请对下面的文章片段用中英文做概述,文件名是{os.path.relpath(fp, project_folder)},' \
|
35 |
+
f'文章内容是 ```{file_content}```'
|
36 |
+
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 假设你是论文审稿专家,请对下面的文章片段做概述: {os.path.abspath(fp)}'
|
37 |
+
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
38 |
+
yield chatbot, history, '正常'
|
39 |
+
|
40 |
+
if not fast_debug:
|
41 |
+
msg = '正常'
|
42 |
+
# ** gpt request **
|
43 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature,
|
44 |
+
history=[]) # 带超时倒计时
|
45 |
+
chatbot[-1] = (i_say_show_user, gpt_say)
|
46 |
+
history.append(i_say_show_user);
|
47 |
+
history.append(gpt_say)
|
48 |
+
yield chatbot, history, msg
|
49 |
+
if not fast_debug: time.sleep(2)
|
50 |
+
|
51 |
+
"""
|
52 |
+
# 可按需启用
|
53 |
+
i_say = f'根据你上述的分析,对全文进行概括,用学术性语言写一段中文摘要,然后再写一篇英文的。'
|
54 |
+
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
55 |
+
yield chatbot, history, '正常'
|
56 |
+
|
57 |
+
|
58 |
+
i_say = f'我想让你做一个论文写作导师。您的任务是使用人工智能工具(例如自然语言处理)提供有关如何改进其上述文章的反馈。' \
|
59 |
+
f'您还应该利用您在有效写作技巧方面的修辞知识和经验来建议作者可以更好地以书面形式表达他们的想法和想法的方法。' \
|
60 |
+
f'根据你之前的分析,提出建议'
|
61 |
+
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
62 |
+
yield chatbot, history, '正常'
|
63 |
+
|
64 |
+
"""
|
65 |
+
|
66 |
+
if not fast_debug:
|
67 |
+
msg = '正常'
|
68 |
+
# ** gpt request **
|
69 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say, chatbot, top_p, temperature,
|
70 |
+
history=history) # 带超时倒计时
|
71 |
+
|
72 |
+
chatbot[-1] = (i_say, gpt_say)
|
73 |
+
history.append(i_say)
|
74 |
+
history.append(gpt_say)
|
75 |
+
yield chatbot, history, msg
|
76 |
+
res = write_results_to_file(history)
|
77 |
+
chatbot.append(("完成了吗?", res))
|
78 |
+
yield chatbot, history, msg
|
79 |
+
|
80 |
+
|
81 |
+
@CatchException
|
82 |
+
def 总结word文档(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
83 |
+
import glob, os
|
84 |
+
|
85 |
+
# 基本信息:功能、贡献者
|
86 |
+
chatbot.append([
|
87 |
+
"函数插件功能?",
|
88 |
+
"批量总结Word文档。函数插件贡献者: JasonGuo1"])
|
89 |
+
yield chatbot, history, '正常'
|
90 |
+
|
91 |
+
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
92 |
+
try:
|
93 |
+
from docx import Document
|
94 |
+
except:
|
95 |
+
report_execption(chatbot, history,
|
96 |
+
a=f"解析项目: {txt}",
|
97 |
+
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。")
|
98 |
+
yield chatbot, history, '正常'
|
99 |
+
return
|
100 |
+
|
101 |
+
# 清空历史,以免输入溢出
|
102 |
+
history = []
|
103 |
+
|
104 |
+
# 检测输入参数,如没有给定输入参数,直接退出
|
105 |
+
if os.path.exists(txt):
|
106 |
+
project_folder = txt
|
107 |
+
else:
|
108 |
+
if txt == "": txt = '空空如也的输入栏'
|
109 |
+
report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
110 |
+
yield chatbot, history, '正常'
|
111 |
+
return
|
112 |
+
|
113 |
+
# 搜索需���处理的文件清单
|
114 |
+
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.docx', recursive=True)] + \
|
115 |
+
[f for f in glob.glob(f'{project_folder}/**/*.doc', recursive=True)]
|
116 |
+
# [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] + \
|
117 |
+
# [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)] + \
|
118 |
+
# [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)]
|
119 |
+
|
120 |
+
# 如果没找到任何文件
|
121 |
+
if len(file_manifest) == 0:
|
122 |
+
report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.docx或doc文件: {txt}")
|
123 |
+
yield chatbot, history, '正常'
|
124 |
+
return
|
125 |
+
|
126 |
+
# 开始正式执行任务
|
127 |
+
yield from 解析docx(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)
|
crazy_functions/批量总结PDF文档.py
CHANGED
@@ -1,7 +1,61 @@
|
|
1 |
from predict import predict_no_ui
|
2 |
from toolbox import CatchException, report_execption, write_results_to_file, predict_no_ui_but_counting_down
|
|
|
|
|
3 |
fast_debug = False
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
def 解析PDF(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
|
7 |
import time, glob, os, fitz
|
@@ -11,6 +65,7 @@ def 解析PDF(file_manifest, project_folder, top_p, temperature, chatbot, histor
|
|
11 |
file_content = ""
|
12 |
for page in doc:
|
13 |
file_content += page.get_text()
|
|
|
14 |
print(file_content)
|
15 |
|
16 |
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
@@ -58,7 +113,7 @@ def 批量总结PDF文档(txt, top_p, temperature, chatbot, history, systemPromp
|
|
58 |
# 基本信息:功能、贡献者
|
59 |
chatbot.append([
|
60 |
"函数插件功能?",
|
61 |
-
"批量总结PDF文档。函数插件贡献者: ValeriaWong"])
|
62 |
yield chatbot, history, '正常'
|
63 |
|
64 |
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
|
|
1 |
from predict import predict_no_ui
|
2 |
from toolbox import CatchException, report_execption, write_results_to_file, predict_no_ui_but_counting_down
|
3 |
+
import re
|
4 |
+
import unicodedata
|
5 |
fast_debug = False
|
6 |
|
7 |
+
def is_paragraph_break(match):
|
8 |
+
"""
|
9 |
+
根据给定的匹配结果来判断换行符是否表示段落分隔。
|
10 |
+
如果换行符前为句子结束标志(句号,感叹号,问号),且下一个字符为大写字母,则换行符更有可能表示段落分隔。
|
11 |
+
也可以根据之前的内容长度来判断段落是否已经足够长。
|
12 |
+
"""
|
13 |
+
prev_char, next_char = match.groups()
|
14 |
+
|
15 |
+
# 句子结束标志
|
16 |
+
sentence_endings = ".!?"
|
17 |
+
|
18 |
+
# 设定一个最小段落长度阈值
|
19 |
+
min_paragraph_length = 140
|
20 |
+
|
21 |
+
if prev_char in sentence_endings and next_char.isupper() and len(match.string[:match.start(1)]) > min_paragraph_length:
|
22 |
+
return "\n\n"
|
23 |
+
else:
|
24 |
+
return " "
|
25 |
+
|
26 |
+
def normalize_text(text):
|
27 |
+
"""
|
28 |
+
通过把连字(ligatures)等文本特殊符号转换为其基本形式来对文本进行归一化处理。
|
29 |
+
例如,将连字 "fi" 转换为 "f" 和 "i"。
|
30 |
+
"""
|
31 |
+
# 对文本进行归一化处理,分解连字
|
32 |
+
normalized_text = unicodedata.normalize("NFKD", text)
|
33 |
+
|
34 |
+
# 替换其他特殊字符
|
35 |
+
cleaned_text = re.sub(r'[^\x00-\x7F]+', '', normalized_text)
|
36 |
+
|
37 |
+
return cleaned_text
|
38 |
+
|
39 |
+
def clean_text(raw_text):
|
40 |
+
"""
|
41 |
+
对从 PDF 提取出的原始文本进行清洗和格式化处理。
|
42 |
+
1. 对原始文本进行归一化处理。
|
43 |
+
2. 替换跨行的连词,例如 “Espe-\ncially” 转换为 “Especially”。
|
44 |
+
3. 根据 heuristic 规则判断换行符是否是段落分隔,并相应地进行替换。
|
45 |
+
"""
|
46 |
+
# 对文本进行归一化处理
|
47 |
+
normalized_text = normalize_text(raw_text)
|
48 |
+
|
49 |
+
# 替换跨行的连词
|
50 |
+
text = re.sub(r'(\w+-\n\w+)', lambda m: m.group(1).replace('-\n', ''), normalized_text)
|
51 |
+
|
52 |
+
# 根据前后相邻字符的特点,找到原文本中的换行符
|
53 |
+
newlines = re.compile(r'(\S)\n(\S)')
|
54 |
+
|
55 |
+
# 根据 heuristic 规则,用空格或段落分隔符替换原换行符
|
56 |
+
final_text = re.sub(newlines, lambda m: m.group(1) + is_paragraph_break(m) + m.group(2), text)
|
57 |
+
|
58 |
+
return final_text.strip()
|
59 |
|
60 |
def 解析PDF(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
|
61 |
import time, glob, os, fitz
|
|
|
65 |
file_content = ""
|
66 |
for page in doc:
|
67 |
file_content += page.get_text()
|
68 |
+
file_content = clean_text(file_content)
|
69 |
print(file_content)
|
70 |
|
71 |
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
|
|
113 |
# 基本信息:功能、贡献者
|
114 |
chatbot.append([
|
115 |
"函数插件功能?",
|
116 |
+
"批量总结PDF文档。函数插件贡献者: ValeriaWong,Eralien"])
|
117 |
yield chatbot, history, '正常'
|
118 |
|
119 |
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
crazy_functions/批量总结PDF文档pdfminer.py
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from predict import predict_no_ui
|
2 |
+
from toolbox import CatchException, report_execption, write_results_to_file, predict_no_ui_but_counting_down
|
3 |
+
|
4 |
+
fast_debug = False
|
5 |
+
|
6 |
+
def readPdf(pdfPath):
|
7 |
+
"""
|
8 |
+
读取pdf文件,返回文本内容
|
9 |
+
"""
|
10 |
+
import pdfminer
|
11 |
+
from pdfminer.pdfparser import PDFParser
|
12 |
+
from pdfminer.pdfdocument import PDFDocument
|
13 |
+
from pdfminer.pdfpage import PDFPage, PDFTextExtractionNotAllowed
|
14 |
+
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
|
15 |
+
from pdfminer.pdfdevice import PDFDevice
|
16 |
+
from pdfminer.layout import LAParams
|
17 |
+
from pdfminer.converter import PDFPageAggregator
|
18 |
+
|
19 |
+
fp = open(pdfPath, 'rb')
|
20 |
+
|
21 |
+
# Create a PDF parser object associated with the file object
|
22 |
+
parser = PDFParser(fp)
|
23 |
+
|
24 |
+
# Create a PDF document object that stores the document structure.
|
25 |
+
# Password for initialization as 2nd parameter
|
26 |
+
document = PDFDocument(parser)
|
27 |
+
# Check if the document allows text extraction. If not, abort.
|
28 |
+
if not document.is_extractable:
|
29 |
+
raise PDFTextExtractionNotAllowed
|
30 |
+
|
31 |
+
# Create a PDF resource manager object that stores shared resources.
|
32 |
+
rsrcmgr = PDFResourceManager()
|
33 |
+
|
34 |
+
# Create a PDF device object.
|
35 |
+
# device = PDFDevice(rsrcmgr)
|
36 |
+
|
37 |
+
# BEGIN LAYOUT ANALYSIS.
|
38 |
+
# Set parameters for analysis.
|
39 |
+
laparams = LAParams(
|
40 |
+
char_margin=10.0,
|
41 |
+
line_margin=0.2,
|
42 |
+
boxes_flow=0.2,
|
43 |
+
all_texts=False,
|
44 |
+
)
|
45 |
+
# Create a PDF page aggregator object.
|
46 |
+
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
|
47 |
+
# Create a PDF interpreter object.
|
48 |
+
interpreter = PDFPageInterpreter(rsrcmgr, device)
|
49 |
+
|
50 |
+
# loop over all pages in the document
|
51 |
+
outTextList = []
|
52 |
+
for page in PDFPage.create_pages(document):
|
53 |
+
# read the page into a layout object
|
54 |
+
interpreter.process_page(page)
|
55 |
+
layout = device.get_result()
|
56 |
+
for obj in layout._objs:
|
57 |
+
if isinstance(obj, pdfminer.layout.LTTextBoxHorizontal):
|
58 |
+
# print(obj.get_text())
|
59 |
+
outTextList.append(obj.get_text())
|
60 |
+
|
61 |
+
return outTextList
|
62 |
+
|
63 |
+
|
64 |
+
def 解析Paper(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt):
|
65 |
+
import time, glob, os
|
66 |
+
from bs4 import BeautifulSoup
|
67 |
+
print('begin analysis on:', file_manifest)
|
68 |
+
for index, fp in enumerate(file_manifest):
|
69 |
+
if ".tex" in fp:
|
70 |
+
with open(fp, 'r', encoding='utf-8') as f:
|
71 |
+
file_content = f.read()
|
72 |
+
if ".pdf" in fp.lower():
|
73 |
+
file_content = readPdf(fp)
|
74 |
+
file_content = BeautifulSoup(''.join(file_content), features="lxml").body.text.encode('gbk', 'ignore').decode('gbk')
|
75 |
+
|
76 |
+
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
77 |
+
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
78 |
+
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
79 |
+
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
80 |
+
print('[1] yield chatbot, history')
|
81 |
+
yield chatbot, history, '正常'
|
82 |
+
|
83 |
+
if not fast_debug:
|
84 |
+
msg = '正常'
|
85 |
+
# ** gpt request **
|
86 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[]) # 带超时倒计时
|
87 |
+
|
88 |
+
print('[2] end gpt req')
|
89 |
+
chatbot[-1] = (i_say_show_user, gpt_say)
|
90 |
+
history.append(i_say_show_user); history.append(gpt_say)
|
91 |
+
print('[3] yield chatbot, history')
|
92 |
+
yield chatbot, history, msg
|
93 |
+
print('[4] next')
|
94 |
+
if not fast_debug: time.sleep(2)
|
95 |
+
|
96 |
+
all_file = ', '.join([os.path.relpath(fp, project_folder) for index, fp in enumerate(file_manifest)])
|
97 |
+
i_say = f'根据以上你自己的分析,对全文进行概括,用学术性语言写一段中文摘要,然后再写一段英文摘要(包括{all_file})。'
|
98 |
+
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
99 |
+
yield chatbot, history, '正常'
|
100 |
+
|
101 |
+
if not fast_debug:
|
102 |
+
msg = '正常'
|
103 |
+
# ** gpt request **
|
104 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say, chatbot, top_p, temperature, history=history) # 带超时倒计时
|
105 |
+
|
106 |
+
chatbot[-1] = (i_say, gpt_say)
|
107 |
+
history.append(i_say); history.append(gpt_say)
|
108 |
+
yield chatbot, history, msg
|
109 |
+
res = write_results_to_file(history)
|
110 |
+
chatbot.append(("完成了吗?", res))
|
111 |
+
yield chatbot, history, msg
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
@CatchException
|
116 |
+
def 批量总结PDF文档pdfminer(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
117 |
+
history = [] # 清空历史,以免输入溢出
|
118 |
+
import glob, os
|
119 |
+
|
120 |
+
# 基本信息:功能、贡献者
|
121 |
+
chatbot.append([
|
122 |
+
"函数插件功能?",
|
123 |
+
"批量总结PDF文档,此版本使用pdfminer插件,带token约简功能。函数插件贡献者: Euclid-Jie。"])
|
124 |
+
yield chatbot, history, '正常'
|
125 |
+
|
126 |
+
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
127 |
+
try:
|
128 |
+
import pdfminer, bs4
|
129 |
+
except:
|
130 |
+
report_execption(chatbot, history,
|
131 |
+
a = f"解析项目: {txt}",
|
132 |
+
b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pdfminer beautifulsoup4```。")
|
133 |
+
yield chatbot, history, '正常'
|
134 |
+
return
|
135 |
+
if os.path.exists(txt):
|
136 |
+
project_folder = txt
|
137 |
+
else:
|
138 |
+
if txt == "": txt = '空空如也的输入栏'
|
139 |
+
report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
140 |
+
yield chatbot, history, '正常'
|
141 |
+
return
|
142 |
+
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] + \
|
143 |
+
[f for f in glob.glob(f'{project_folder}/**/*.pdf', recursive=True)] # + \
|
144 |
+
# [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)] + \
|
145 |
+
# [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)]
|
146 |
+
if len(file_manifest) == 0:
|
147 |
+
report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex或pdf文件: {txt}")
|
148 |
+
yield chatbot, history, '正常'
|
149 |
+
return
|
150 |
+
yield from 解析Paper(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)
|
151 |
+
|
crazy_functions/解析项目源代码.py
CHANGED
@@ -50,7 +50,8 @@ def 解析源代码(file_manifest, project_folder, top_p, temperature, chatbot,
|
|
50 |
def 解析项目本身(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
51 |
history = [] # 清空历史,以免输入溢出
|
52 |
import time, glob, os
|
53 |
-
file_manifest = [f for f in glob.glob('
|
|
|
54 |
for index, fp in enumerate(file_manifest):
|
55 |
# if 'test_project' in fp: continue
|
56 |
with open(fp, 'r', encoding='utf-8') as f:
|
@@ -65,7 +66,7 @@ def 解析项目本身(txt, top_p, temperature, chatbot, history, systemPromptTx
|
|
65 |
if not fast_debug:
|
66 |
# ** gpt request **
|
67 |
# gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature)
|
68 |
-
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[]) # 带超时倒计时
|
69 |
|
70 |
chatbot[-1] = (i_say_show_user, gpt_say)
|
71 |
history.append(i_say_show_user); history.append(gpt_say)
|
@@ -79,7 +80,7 @@ def 解析项目本身(txt, top_p, temperature, chatbot, history, systemPromptTx
|
|
79 |
if not fast_debug:
|
80 |
# ** gpt request **
|
81 |
# gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature, history=history)
|
82 |
-
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say, chatbot, top_p, temperature, history=history) # 带超时倒计时
|
83 |
|
84 |
chatbot[-1] = (i_say, gpt_say)
|
85 |
history.append(i_say); history.append(gpt_say)
|
|
|
50 |
def 解析项目本身(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
51 |
history = [] # 清空历史,以免输入溢出
|
52 |
import time, glob, os
|
53 |
+
file_manifest = [f for f in glob.glob('./*.py') if ('test_project' not in f) and ('gpt_log' not in f)] + \
|
54 |
+
[f for f in glob.glob('./crazy_functions/*.py') if ('test_project' not in f) and ('gpt_log' not in f)]
|
55 |
for index, fp in enumerate(file_manifest):
|
56 |
# if 'test_project' in fp: continue
|
57 |
with open(fp, 'r', encoding='utf-8') as f:
|
|
|
66 |
if not fast_debug:
|
67 |
# ** gpt request **
|
68 |
# gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature)
|
69 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[], long_connection=True) # 带超时倒计时
|
70 |
|
71 |
chatbot[-1] = (i_say_show_user, gpt_say)
|
72 |
history.append(i_say_show_user); history.append(gpt_say)
|
|
|
80 |
if not fast_debug:
|
81 |
# ** gpt request **
|
82 |
# gpt_say = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature, history=history)
|
83 |
+
gpt_say = yield from predict_no_ui_but_counting_down(i_say, i_say, chatbot, top_p, temperature, history=history, long_connection=True) # 带超时倒计时
|
84 |
|
85 |
chatbot[-1] = (i_say, gpt_say)
|
86 |
history.append(i_say); history.append(gpt_say)
|
crazy_functions/高级功能函数模板.py
CHANGED
@@ -5,13 +5,13 @@ import datetime
|
|
5 |
@CatchException
|
6 |
def 高阶功能模板函数(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
7 |
history = [] # 清空历史,以免输入溢出
|
8 |
-
chatbot.append(("这是什么功能?", "[Local Message]
|
9 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
10 |
|
11 |
for i in range(5):
|
12 |
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
13 |
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
14 |
-
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE
|
15 |
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
16 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
17 |
|
|
|
5 |
@CatchException
|
6 |
def 高阶功能模板函数(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
|
7 |
history = [] # 清空历史,以免输入溢出
|
8 |
+
chatbot.append(("这是什么功能?", "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板。为了做到简单易读,该函数只有25行代码,所以不会实时反馈文字流或心跳,请耐心等待程序输出完成。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!"))
|
9 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
10 |
|
11 |
for i in range(5):
|
12 |
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
13 |
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
14 |
+
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
15 |
chatbot.append((i_say, "[Local Message] waiting gpt response."))
|
16 |
yield chatbot, history, '正常' # 由于请求gpt需要一段时间,我们先及时地做一次状态显示
|
17 |
|
functional.py
CHANGED
@@ -21,12 +21,20 @@ def get_functionals():
|
|
21 |
"Suffix": r"",
|
22 |
},
|
23 |
"查找语法错误": {
|
24 |
-
"Prefix": r"
|
25 |
-
r"
|
26 |
-
r"
|
27 |
-
r"If you find grammar or spelling mistakes, please list mistakes you find in a two-column markdown table, " +
|
28 |
r"put the original text the first column, " +
|
29 |
-
r"put the corrected text in the second column and highlight the key words you fixed."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
"Suffix": r"",
|
31 |
"PreProcess": clear_line_break, # 预处理:清除换行符
|
32 |
},
|
@@ -34,9 +42,17 @@ def get_functionals():
|
|
34 |
"Prefix": r"Please translate following sentence to English:" + "\n\n",
|
35 |
"Suffix": r"",
|
36 |
},
|
37 |
-
"
|
38 |
-
"Prefix": r"
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
},
|
41 |
"英译中": {
|
42 |
"Prefix": r"请翻译成中文:" + "\n\n",
|
|
|
21 |
"Suffix": r"",
|
22 |
},
|
23 |
"查找语法错误": {
|
24 |
+
"Prefix": r"Can you help me ensure that the grammar and the spelling is correct? " +
|
25 |
+
r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good." +
|
26 |
+
r"If you find grammar or spelling mistakes, please list mistakes you find in a two-column markdown table, " +
|
|
|
27 |
r"put the original text the first column, " +
|
28 |
+
r"put the corrected text in the second column and highlight the key words you fixed.""\n"
|
29 |
+
r"Example:""\n"
|
30 |
+
r"Paragraph: How is you? Do you knows what is it?""\n"
|
31 |
+
r"| Original sentence | Corrected sentence |""\n"
|
32 |
+
r"| :--- | :--- |""\n"
|
33 |
+
r"| How **is** you? | How **are** you? |""\n"
|
34 |
+
r"| Do you **knows** what **is** **it**? | Do you **know** what **it** **is** ? |""\n"
|
35 |
+
r"Below is a paragraph from an academic paper. "
|
36 |
+
r"You need to report all grammar and spelling mistakes as the example before."
|
37 |
+
+ "\n\n",
|
38 |
"Suffix": r"",
|
39 |
"PreProcess": clear_line_break, # 预处理:清除换行符
|
40 |
},
|
|
|
42 |
"Prefix": r"Please translate following sentence to English:" + "\n\n",
|
43 |
"Suffix": r"",
|
44 |
},
|
45 |
+
"学术中英互译": {
|
46 |
+
"Prefix": r"I want you to act as a scientific English-Chinese translator, " +
|
47 |
+
r"I will provide you with some paragraphs in one language " +
|
48 |
+
r"and your task is to accurately and academically translate the paragraphs only into the other language. " +
|
49 |
+
r"Do not repeat the original provided paragraphs after translation. " +
|
50 |
+
r"You should use artificial intelligence tools, " +
|
51 |
+
r"such as natural language processing, and rhetorical knowledge " +
|
52 |
+
r"and experience about effective writing techniques to reply. " +
|
53 |
+
r"I'll give you my paragraphs as follows, tell me what language it is written in, and then translate:" + "\n\n",
|
54 |
+
"Suffix": "",
|
55 |
+
"Color": "secondary",
|
56 |
},
|
57 |
"英译中": {
|
58 |
"Prefix": r"请翻译成中文:" + "\n\n",
|
functional_crazy.py
CHANGED
@@ -1,9 +1,12 @@
|
|
|
|
|
|
1 |
# UserVisibleLevel是过滤器参数。
|
2 |
# 由于UI界面空间有限,所以通过这种方式决定UI界面中显示哪些插件
|
3 |
# 默认函数插件 VisibleLevel 是 0
|
4 |
# 当 UserVisibleLevel >= 函数插件的 VisibleLevel 时,该函数插件才会被显示出来
|
5 |
UserVisibleLevel = 1
|
6 |
|
|
|
7 |
def get_crazy_functionals():
|
8 |
from crazy_functions.读文章写摘要 import 读文章写摘要
|
9 |
from crazy_functions.生成函数注释 import 批量生成函数注释
|
@@ -15,10 +18,11 @@ def get_crazy_functionals():
|
|
15 |
from crazy_functions.代码重写为全英文_多线程 import 全项目切换英文
|
16 |
|
17 |
function_plugins = {
|
18 |
-
"
|
|
|
19 |
"Function": 解析项目本身
|
20 |
},
|
21 |
-
"解析整个
|
22 |
"Color": "stop", # 按钮颜色
|
23 |
"Function": 解析一个Python项目
|
24 |
},
|
@@ -26,11 +30,12 @@ def get_crazy_functionals():
|
|
26 |
"Color": "stop", # 按钮颜色
|
27 |
"Function": 解析一个C项目的头文件
|
28 |
},
|
29 |
-
"解析整个C
|
30 |
"Color": "stop", # 按钮颜色
|
|
|
31 |
"Function": 解析一个C项目
|
32 |
},
|
33 |
-
"读
|
34 |
"Color": "stop", # 按钮颜色
|
35 |
"Function": 读文章写摘要
|
36 |
},
|
@@ -39,20 +44,33 @@ def get_crazy_functionals():
|
|
39 |
"Function": 批量生成函数注释
|
40 |
},
|
41 |
"[多线程demo] 把本项目源代码切换成全英文": {
|
42 |
-
|
|
|
43 |
},
|
44 |
"[函数插件模板demo] 历史上的今天": {
|
45 |
-
|
|
|
46 |
},
|
47 |
}
|
48 |
|
49 |
-
# VisibleLevel=1
|
50 |
if UserVisibleLevel >= 1:
|
51 |
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
|
|
|
|
52 |
function_plugins.update({
|
53 |
"[仅供开发调试] 批量总结PDF文档": {
|
54 |
"Color": "stop",
|
55 |
-
"Function": 批量总结PDF文档
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
},
|
57 |
})
|
58 |
|
|
|
1 |
+
from toolbox import HotReload # HotReload 的意思是热更新,修改函数插件后,不需要重启程序,代码直接生效
|
2 |
+
|
3 |
# UserVisibleLevel是过滤器参数。
|
4 |
# 由于UI界面空间有限,所以通过这种方式决定UI界面中显示哪些插件
|
5 |
# 默认函数插件 VisibleLevel 是 0
|
6 |
# 当 UserVisibleLevel >= 函数插件的 VisibleLevel 时,该函数插件才会被显示出来
|
7 |
UserVisibleLevel = 1
|
8 |
|
9 |
+
|
10 |
def get_crazy_functionals():
|
11 |
from crazy_functions.读文章写摘要 import 读文章写摘要
|
12 |
from crazy_functions.生成函数注释 import 批量生成函数注释
|
|
|
18 |
from crazy_functions.代码重写为全英文_多线程 import 全项目切换英文
|
19 |
|
20 |
function_plugins = {
|
21 |
+
"请解析并解构此项目本身(源码自译解)": {
|
22 |
+
"AsButton": False, # 加入下拉菜单中
|
23 |
"Function": 解析项目本身
|
24 |
},
|
25 |
+
"解析整个Py项目": {
|
26 |
"Color": "stop", # 按钮颜色
|
27 |
"Function": 解析一个Python项目
|
28 |
},
|
|
|
30 |
"Color": "stop", # 按钮颜色
|
31 |
"Function": 解析一个C项目的头文件
|
32 |
},
|
33 |
+
"解析整个C++项目(.cpp/.h)": {
|
34 |
"Color": "stop", # 按钮颜色
|
35 |
+
"AsButton": False, # 加入下拉菜单中
|
36 |
"Function": 解析一个C项目
|
37 |
},
|
38 |
+
"读Tex论文写摘要": {
|
39 |
"Color": "stop", # 按钮颜色
|
40 |
"Function": 读文章写摘要
|
41 |
},
|
|
|
44 |
"Function": 批量生成函数注释
|
45 |
},
|
46 |
"[多线程demo] 把本项目源代码切换成全英文": {
|
47 |
+
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
|
48 |
+
"Function": HotReload(全项目切换英文)
|
49 |
},
|
50 |
"[函数插件模板demo] 历史上的今天": {
|
51 |
+
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
|
52 |
+
"Function": HotReload(高阶功能模板函数)
|
53 |
},
|
54 |
}
|
55 |
|
56 |
+
# VisibleLevel=1 经过测试,但功能上距离达到完美状态还差一点点
|
57 |
if UserVisibleLevel >= 1:
|
58 |
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
59 |
+
from crazy_functions.批量总结PDF文档pdfminer import 批量总结PDF文档pdfminer
|
60 |
+
from crazy_functions.总结word文档 import 总结word文档
|
61 |
function_plugins.update({
|
62 |
"[仅供开发调试] 批量总结PDF文档": {
|
63 |
"Color": "stop",
|
64 |
+
"Function": HotReload(批量总结PDF文档) # HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
|
65 |
+
},
|
66 |
+
"[仅供开发调试] 批量总结PDF文档pdfminer": {
|
67 |
+
"Color": "stop",
|
68 |
+
"AsButton": False, # 加入下拉菜单中
|
69 |
+
"Function": HotReload(批量总结PDF文档pdfminer)
|
70 |
+
},
|
71 |
+
"[仅供开发调试] 批量总结Word文档": {
|
72 |
+
"Color": "stop",
|
73 |
+
"Function": HotReload(总结word文档)
|
74 |
},
|
75 |
})
|
76 |
|
main.py
CHANGED
@@ -4,9 +4,8 @@ from predict import predict
|
|
4 |
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf
|
5 |
|
6 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
7 |
-
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = \
|
8 |
-
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
9 |
-
|
10 |
|
11 |
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
12 |
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
@@ -17,34 +16,33 @@ title_html = """<h1 align="center">ChatGPT 学术优化</h1>"""
|
|
17 |
|
18 |
# 问询记录, python 版本建议3.9+(越新越好)
|
19 |
import logging
|
20 |
-
os.makedirs(
|
21 |
-
try:logging.basicConfig(filename=
|
22 |
-
except:logging.basicConfig(filename=
|
23 |
-
print(
|
24 |
|
25 |
# 一些普通功能模块
|
26 |
from functional import get_functionals
|
27 |
functional = get_functionals()
|
28 |
|
29 |
-
#
|
30 |
from functional_crazy import get_crazy_functionals
|
31 |
-
|
32 |
|
33 |
# 处理markdown文本格式的转变
|
34 |
gr.Chatbot.postprocess = format_io
|
35 |
|
36 |
# 做一些外观色彩上的调整
|
37 |
-
from theme import adjust_theme
|
38 |
set_theme = adjust_theme()
|
39 |
|
40 |
cancel_handles = []
|
41 |
-
with gr.Blocks(theme=set_theme, analytics_enabled=False) as demo:
|
42 |
gr.HTML(title_html)
|
43 |
-
with gr.Row():
|
44 |
with gr.Column(scale=2):
|
45 |
chatbot = gr.Chatbot()
|
46 |
-
chatbot.style(height=
|
47 |
-
chatbot.style()
|
48 |
history = gr.State([])
|
49 |
with gr.Column(scale=1):
|
50 |
with gr.Row():
|
@@ -56,48 +54,80 @@ with gr.Blocks(theme=set_theme, analytics_enabled=False) as demo:
|
|
56 |
stopBtn = gr.Button("停止", variant="secondary"); stopBtn.style(size="sm")
|
57 |
with gr.Row():
|
58 |
from check_proxy import check_proxy
|
59 |
-
|
60 |
-
with gr.Accordion("基础功能区", open=True):
|
61 |
with gr.Row():
|
62 |
for k in functional:
|
63 |
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
|
64 |
functional[k]["Button"] = gr.Button(k, variant=variant)
|
65 |
-
with gr.Accordion("函数插件区", open=True):
|
66 |
with gr.Row():
|
67 |
gr.Markdown("注意:以下“红颜色”标识的函数插件需从input区读取路径作为参数.")
|
68 |
with gr.Row():
|
69 |
-
for k in
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
with gr.Row():
|
73 |
-
with gr.Accordion("
|
74 |
-
file_upload = gr.Files(label=
|
75 |
with gr.Accordion("展开SysPrompt & GPT参数 & 交互界面布局", open=False):
|
76 |
system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
|
77 |
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
|
78 |
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
|
79 |
-
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区"
|
80 |
-
label="显示功能区")
|
81 |
-
predict_args = dict(fn=predict, inputs=[txt, top_p, temperature, chatbot, history, system_prompt], outputs=[chatbot, history, statusDisplay], show_progress=True)
|
82 |
-
empty_txt_args = dict(fn=lambda: "", inputs=[], outputs=[txt]) # 用于在提交后清空输入栏
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
for k in functional:
|
90 |
-
click_handle = functional[k]["Button"].click(predict,
|
91 |
-
[txt, top_p, temperature, chatbot, history, system_prompt, gr.State(True), gr.State(k)], [chatbot, history, statusDisplay], show_progress=True)
|
92 |
cancel_handles.append(click_handle)
|
|
|
93 |
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt], [chatbot, txt])
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
)
|
98 |
-
|
99 |
-
except: pass
|
100 |
cancel_handles.append(click_handle)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
102 |
|
103 |
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
@@ -106,7 +136,7 @@ def auto_opentab_delay():
|
|
106 |
print(f"如果浏览器没有自动打开,请复制并转到以下URL: http://localhost:{PORT}")
|
107 |
def open():
|
108 |
time.sleep(2)
|
109 |
-
webbrowser.open_new_tab(f
|
110 |
threading.Thread(target=open, name="open-browser", daemon=True).start()
|
111 |
|
112 |
auto_opentab_delay()
|
|
|
4 |
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf
|
5 |
|
6 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
7 |
+
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT = \
|
8 |
+
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT')
|
|
|
9 |
|
10 |
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
11 |
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
|
|
16 |
|
17 |
# 问询记录, python 版本建议3.9+(越新越好)
|
18 |
import logging
|
19 |
+
os.makedirs("gpt_log", exist_ok=True)
|
20 |
+
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
|
21 |
+
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
|
22 |
+
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
|
23 |
|
24 |
# 一些普通功能模块
|
25 |
from functional import get_functionals
|
26 |
functional = get_functionals()
|
27 |
|
28 |
+
# 高级函数插件
|
29 |
from functional_crazy import get_crazy_functionals
|
30 |
+
crazy_fns = get_crazy_functionals()
|
31 |
|
32 |
# 处理markdown文本格式的转变
|
33 |
gr.Chatbot.postprocess = format_io
|
34 |
|
35 |
# 做一些外观色彩上的调整
|
36 |
+
from theme import adjust_theme, advanced_css
|
37 |
set_theme = adjust_theme()
|
38 |
|
39 |
cancel_handles = []
|
40 |
+
with gr.Blocks(theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
|
41 |
gr.HTML(title_html)
|
42 |
+
with gr.Row().style(equal_height=True):
|
43 |
with gr.Column(scale=2):
|
44 |
chatbot = gr.Chatbot()
|
45 |
+
chatbot.style(height=CHATBOT_HEIGHT)
|
|
|
46 |
history = gr.State([])
|
47 |
with gr.Column(scale=1):
|
48 |
with gr.Row():
|
|
|
54 |
stopBtn = gr.Button("停止", variant="secondary"); stopBtn.style(size="sm")
|
55 |
with gr.Row():
|
56 |
from check_proxy import check_proxy
|
57 |
+
status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {check_proxy(proxies)}")
|
58 |
+
with gr.Accordion("基础功能区", open=True) as area_basic_fn:
|
59 |
with gr.Row():
|
60 |
for k in functional:
|
61 |
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
|
62 |
functional[k]["Button"] = gr.Button(k, variant=variant)
|
63 |
+
with gr.Accordion("函数插件区", open=True) as area_crazy_fn:
|
64 |
with gr.Row():
|
65 |
gr.Markdown("注意:以下“红颜色”标识的函数插件需从input区读取路径作为参数.")
|
66 |
with gr.Row():
|
67 |
+
for k in crazy_fns:
|
68 |
+
if not crazy_fns[k].get("AsButton", True): continue
|
69 |
+
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
|
70 |
+
crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
|
71 |
+
with gr.Row():
|
72 |
+
with gr.Accordion("更多函数插件", open=True):
|
73 |
+
dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
|
74 |
+
with gr.Column(scale=1):
|
75 |
+
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="").style(container=False)
|
76 |
+
with gr.Column(scale=1):
|
77 |
+
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary")
|
78 |
with gr.Row():
|
79 |
+
with gr.Accordion("点击展开“文件上传区”。上传本地文件可供红色函数插件调用。", open=False) as area_file_up:
|
80 |
+
file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)", file_count="multiple")
|
81 |
with gr.Accordion("展开SysPrompt & GPT参数 & 交互界面布局", open=False):
|
82 |
system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
|
83 |
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
|
84 |
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
|
85 |
+
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区")
|
|
|
|
|
|
|
86 |
|
87 |
+
# 功能区显示开关与功能区的互动
|
88 |
+
def fn_area_visibility(a):
|
89 |
+
ret = {}
|
90 |
+
ret.update({area_basic_fn: gr.update(visible=("基础功能区" in a))})
|
91 |
+
ret.update({area_crazy_fn: gr.update(visible=("函数插件区" in a))})
|
92 |
+
return ret
|
93 |
+
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn] )
|
94 |
+
# 整理反复出现的控件句柄组合
|
95 |
+
input_combo = [txt, top_p, temperature, chatbot, history, system_prompt]
|
96 |
+
output_combo = [chatbot, history, status]
|
97 |
+
predict_args = dict(fn=predict, inputs=input_combo, outputs=output_combo)
|
98 |
+
empty_txt_args = dict(fn=lambda: "", inputs=[], outputs=[txt]) # 用于在提交后清空输入栏
|
99 |
+
# 提交按钮、重置按钮
|
100 |
+
cancel_handles.append(txt.submit(**predict_args)) #; txt.submit(**empty_txt_args) 在提交后清空输入栏
|
101 |
+
cancel_handles.append(submitBtn.click(**predict_args)) #; submitBtn.click(**empty_txt_args) 在提交后清空输入栏
|
102 |
+
resetBtn.click(lambda: ([], [], "已重置"), None, output_combo)
|
103 |
+
# 基础功能区的回调函数注册
|
104 |
for k in functional:
|
105 |
+
click_handle = functional[k]["Button"].click(predict, [*input_combo, gr.State(True), gr.State(k)], output_combo)
|
|
|
106 |
cancel_handles.append(click_handle)
|
107 |
+
# 文件上传区,接收文件后与chatbot的互动
|
108 |
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt], [chatbot, txt])
|
109 |
+
# 函数插件-固定按钮区
|
110 |
+
for k in crazy_fns:
|
111 |
+
if not crazy_fns[k].get("AsButton", True): continue
|
112 |
+
click_handle = crazy_fns[k]["Button"].click(crazy_fns[k]["Function"], [*input_combo, gr.State(PORT)], output_combo)
|
113 |
+
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
|
|
|
114 |
cancel_handles.append(click_handle)
|
115 |
+
# 函数插件-下拉菜单与随变按钮的互动
|
116 |
+
def on_dropdown_changed(k):
|
117 |
+
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
|
118 |
+
return {switchy_bt: gr.update(value=k, variant=variant)}
|
119 |
+
dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt] )
|
120 |
+
# 随变按钮的回调函数注册
|
121 |
+
def route(k, *args, **kwargs):
|
122 |
+
if k in [r"打开插件列表", r"先从插件列表中选择"]: return
|
123 |
+
yield from crazy_fns[k]["Function"](*args, **kwargs)
|
124 |
+
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
|
125 |
+
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
|
126 |
+
def expand_file_area(file_upload, area_file_up):
|
127 |
+
if len(file_upload)>0: return {area_file_up: gr.update(open=True)}
|
128 |
+
click_handle.then(expand_file_area, [file_upload, area_file_up], [area_file_up])
|
129 |
+
cancel_handles.append(click_handle)
|
130 |
+
# 终止按钮的回调函数注册
|
131 |
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
132 |
|
133 |
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
|
|
136 |
print(f"如果浏览器没有自动打开,请复制并转到以下URL: http://localhost:{PORT}")
|
137 |
def open():
|
138 |
time.sleep(2)
|
139 |
+
webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
140 |
threading.Thread(target=open, name="open-browser", daemon=True).start()
|
141 |
|
142 |
auto_opentab_delay()
|
predict.py
CHANGED
@@ -96,13 +96,19 @@ def predict_no_ui_long_connection(inputs, top_p, temperature, history=[], sys_pr
|
|
96 |
except StopIteration: break
|
97 |
if len(chunk)==0: continue
|
98 |
if not chunk.startswith('data:'):
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
102 |
if len(delta) == 0: break
|
103 |
if "role" in delta: continue
|
104 |
if "content" in delta: result += delta["content"]; print(delta["content"], end='')
|
105 |
else: raise RuntimeError("意外Json结构:"+delta)
|
|
|
|
|
106 |
return result
|
107 |
|
108 |
|
|
|
96 |
except StopIteration: break
|
97 |
if len(chunk)==0: continue
|
98 |
if not chunk.startswith('data:'):
|
99 |
+
error_msg = get_full_error(chunk.encode('utf8'), stream_response).decode()
|
100 |
+
if "reduce the length" in error_msg:
|
101 |
+
raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg)
|
102 |
+
else:
|
103 |
+
raise RuntimeError("OpenAI拒绝了请求:" + error_msg)
|
104 |
+
json_data = json.loads(chunk.lstrip('data:'))['choices'][0]
|
105 |
+
delta = json_data["delta"]
|
106 |
if len(delta) == 0: break
|
107 |
if "role" in delta: continue
|
108 |
if "content" in delta: result += delta["content"]; print(delta["content"], end='')
|
109 |
else: raise RuntimeError("意外Json结构:"+delta)
|
110 |
+
if json_data['finish_reason'] == 'length':
|
111 |
+
raise ConnectionAbortedError("正常结束,但显示Token不足。")
|
112 |
return result
|
113 |
|
114 |
|
project_self_analysis.md
CHANGED
@@ -1,88 +1,85 @@
|
|
1 |
-
# chatgpt-academic
|
2 |
-
(Author补充:以下分析均由本项目调用ChatGPT
|
3 |
|
4 |
-
## [0/
|
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 |
-
- crazy_functions.生成函数注释 中的 批量生成函数注释
|
37 |
-
- crazy_functions.解析项目源代码 中的 解析项目本身、解析一个Python项目、解析一个C项目的头文件、解析一个C项目
|
38 |
-
- crazy_functions.高级功能函数模板 中的 高阶功能模板函数
|
39 |
|
40 |
-
|
41 |
|
42 |
-
|
43 |
-
- "[实验] 解析整个py项目(配合input输入框)",包含函数:解析一个Python项目
|
44 |
-
- "[实验] 解析整个C++项目头文件(配合input输入框)",包含函数:解析一个C项目的头文件
|
45 |
-
- "[实验] 解析整个C++项目(配合input输入框)",包含函数:解析一个C项目
|
46 |
-
- "[实验] 读tex论文写摘要(配合input输入框)",包含函数:读文章写摘要
|
47 |
-
- "[实验] 批量生成函数注释(配合input输入框)",包含函数:批量生成函数注释
|
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 |
-
这是一个名为theme.py的程序文件,用于设置Gradio界面的颜色和字体主题。该文件中定义了一个名为adjust_theme()的函数,其作用是返回一个Gradio theme对象,设置了Gradio界面的颜色和字体主题。在该函数里面,使用了Graido可用的颜色列表,主要参数包括primary_hue、neutral_hue、font和font_mono等,用于设置Gradio界面的主题色调、字体等。另外,该函数还实现了一些参数的自定义,如input_background_fill_dark、button_transition、button_shadow_hover等,用于设置Gradio界面的渐变、阴影等特效。如果Gradio版本过于陈旧,该函数会抛出异常并返回None。
|
82 |
-
|
83 |
-
## [9/10] 程序摘要: toolbox.py
|
84 |
-
|
85 |
-
该文件为Python程序文件,文件名为toolbox.py。主要功能包括:
|
86 |
|
87 |
1. 导入markdown、mdtex2html、threading、functools等模块。
|
88 |
2. 定义函数predict_no_ui_but_counting_down,用于生成对话。
|
@@ -99,24 +96,80 @@
|
|
99 |
13. 定义函数on_file_uploaded,用于处理上传文件的操作。
|
100 |
14. 定义函数on_report_generated,用于处理生成报告文件的操作。
|
101 |
|
102 |
-
## 程序的整体功能和构架做出概括。然后用一张markdown表格整理每个文件的功能。
|
103 |
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
-
|
107 |
|
108 |
-
| 文件名 |
|
109 |
-
|
110 |
-
|
|
111 |
-
|
|
112 |
-
|
|
113 |
-
|
|
114 |
-
|
|
115 |
-
|
|
116 |
-
|
|
117 |
-
|
|
118 |
-
| theme.py |
|
119 |
-
| toolbox.py |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
-
|
122 |
|
|
|
1 |
+
# chatgpt-academic项目自译解报告
|
2 |
+
(Author补充:以下分析均由本项目调用ChatGPT一键生成,如果有不准确的地方,全怪GPT😄)
|
3 |
|
4 |
+
## [0/18] 程序摘要: functional_crazy.py
|
5 |
|
6 |
+
这是一个功能扩展的程序,文件名为 `functional_crazy.py`。代码的主要功能是通过提供一系列函数插件,增强程序的功能,让用户可以通过界面中的按钮,快速调用对应的函数插件实现相应的操作。代码中使用了 `HotReload` 函数插件,可以在不重启程序的情况下更新函数插件的代码,让其生效。同时,通过 `UserVisibleLevel` 变量的设置,可以控制哪些插件会在UI界面显示出来。函数插件列表包括了以下功能:解析项目本身、解析一个Python项目、解析一个C++项目头文件、解析一个C++项目、读取文章并生成摘要、批量生成函数注释、全项目切换成英文、批量总结PDF文档、批量总结PDF文档pdfminer、批量总结Word文档、高阶功能模板函数、以及其他未经充分测试的函数插件。
|
7 |
|
8 |
+
## [1/18] 程序摘要: main.py
|
9 |
|
10 |
+
该程序是一个基于Gradio构建的对话生成模型的Web界面示例,包含了以下主要功能:
|
11 |
|
12 |
+
1.加载模型并对用户输入进行响应;
|
13 |
+
2.通过调用外部函数库来获取用户的输入,并在模型生成的过程中进行处理;
|
14 |
+
3.支持用户上传本地文件,供外部函数库调用;
|
15 |
+
4.支持停止当前的生成过程;
|
16 |
+
5.保存用户的历史记录,并将其记录在本地日志文件中,以供后续分析和使用。
|
17 |
|
18 |
+
该程序需要依赖于一些外部库和软件包,如Gradio、torch等。用户需要确保这些依赖项已经安装,并且在运行该程序前对config_private.py配置文件进行相应的修改。
|
19 |
|
20 |
+
## [2/18] 程序摘要: functional.py
|
21 |
|
22 |
+
该文件定义了一个名为“functional”的函数,函数的作用是返回一个包含多个字典(键值对)的字典,每个键值对表示一种功能。该字典的键值由功能名称和对应的数据组成。其中的每个字典都包含4个键值对,分别为“Prefix”、“Suffix”、“Color”和“PreProcess”,分别表示前缀、后缀、按钮颜色和预处理函数。如果某些键值对没有给出,那么程序中默认相应的值,如按钮颜色默认为“secondary”等。每个功能描述了不同的学术润色/翻译/其他服务,如“英语学术润色”、“中文学术润色”、“查找语法错误”等。函数还引用了一个名为“clear_line_break”的函数,用于预处理修改前的文本。
|
23 |
|
24 |
+
## [3/18] 程序摘要: show_math.py
|
25 |
|
26 |
+
该程序文件名为show_math.py,主要用途是将Markdown和LaTeX混合格式转换成带有MathML的HTML格式。该程序通过递归地处理LaTeX和Markdown混合��落逐一转换成HTML/MathML标记出来,并在LaTeX公式创建中进行错误处理。在程序文件中定义了3个变量,分别是incomplete,convError和convert,其中convert函数是用来执行转换的主要函数。程序使用正则表达式进行LaTeX格式和Markdown段落的分割,从而实现转换。如果在Latex转换过程中发生错误,程序将输出相应的错误信息。
|
27 |
|
28 |
+
## [4/18] 程序摘要: predict.py
|
29 |
|
30 |
+
本程序文件的文件名为"./predict.py",主要包含三个函数:
|
31 |
|
32 |
+
1. predict:正常对话时使用,具备完备的交互功能,不可多线程;
|
33 |
+
2. predict_no_ui:高级实验性功能模块调用,不会实时显示在界面上,参数简单,可以多线程并行,方便实现复杂的功能逻辑;
|
34 |
+
3. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程。
|
35 |
|
36 |
+
其中,predict函数用于基础的对话功能,发送至chatGPT,流式获取输出,根据点击的哪个按钮,进行对话预处理等额外操作;predict_no_ui函数用于payload比较大的情况,或者用于实现多线、带嵌套的复杂功能;predict_no_ui_long_connection实现调用predict_no_ui处理长文档时,避免连接断掉的情况,支持多线程。
|
37 |
|
38 |
+
## [5/18] 程序摘要: check_proxy.py
|
39 |
|
40 |
+
该程序文件名为check_proxy.py,主要功能是检查代理服务器的可用性并返回代理服务器的地理位置信息或错误提示。具体实现方式如下:
|
41 |
|
42 |
+
首先使用requests模块向指定网站(https://ipapi.co/json/)发送GET请求,请求结果以JSON格式返回。如果代理服务器参数(proxies)是有效的且没有指明'https'代理,则用默认字典值'无'替代。
|
|
|
|
|
|
|
43 |
|
44 |
+
然后,程序会解析返回的JSON数据,并根据数据中是否包含国家名字字段来判断代理服务器的地理位置。如果有国家名字字段,则将其打印出来并返回代理服务器的相关信息。如果没有国家名字字段,但有错误信息字段,则返回其他错误提示信息。
|
45 |
|
46 |
+
在程序执行前,程序会先设置环境变量no_proxy,并使用toolbox模块中的get_conf函数从配置文件中读取代理参数。
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
+
最后,检测程序会输出检查结果并返回对应的结果字符串。
|
49 |
|
50 |
+
## [6/18] 程序摘要: config_private.py
|
51 |
|
52 |
+
本程序文件名为`config_private.py`,其功能为配置私有信息以便在主程序中使用。主要功能包括:
|
53 |
|
54 |
+
- 配置OpenAI API的密钥和API URL
|
55 |
+
- 配置是否使用代理,如果使用代理配置代理地址和端口
|
56 |
+
- 配置发送请求的超时时间和失败重试次数的限制
|
57 |
+
- 配置并行使用线程数和用户名密码
|
58 |
+
- 提供检查功能以确保API密钥已经正确设置
|
59 |
|
60 |
+
其中,需要特别注意的是:最后一个检查功能要求在运行之前必须将API密钥正确设置,否则程序会直接退出。
|
61 |
|
62 |
+
## [7/18] 程序摘要: config.py
|
63 |
|
64 |
+
该程序文件是一个配置文件,用于配置OpenAI的API参数和优化体验的相关参数,具体包括以下几个步骤:
|
65 |
|
66 |
+
1.设置OpenAI的API密钥。
|
67 |
|
68 |
+
2.选择是否使用代理,如果使用则需要设置代理地址和端口等参数。
|
69 |
|
70 |
+
3.设置请求OpenAI后的超时时间、网页的端口、重试次数、选择的OpenAI模型、API的网址等。
|
71 |
|
72 |
+
4.设置并行使用的线程数和用户名密码。
|
73 |
|
74 |
+
该程序文件的作用为在使用OpenAI API时进行相关参数的配置,以保证请求的正确性和速度,并且优化使用体验。
|
75 |
|
76 |
+
## [8/18] 程序摘要: theme.py
|
77 |
|
78 |
+
该程序是一个自定义Gradio主题的Python模块。主题文件名为"./theme.py"。程序引入了Gradio模块,并定义了一个名为"adjust_theme()"的函数。该函数根据输入值调整Gradio的默认主题,返回一个包含所需自定义属性的主题对象。主题属性包括颜色、字体、过渡、阴影、按钮边框和渐变等。主题颜色列表包括石板色、灰色、锌色、中性色、石头色、红色、橙色、琥珀色、黄色、酸橙色、绿色、祖母绿、青蓝色、青色、天蓝色、蓝色、靛蓝色、紫罗兰色、紫色、洋红色、粉红色和玫瑰色。如果Gradio版本较旧,则不能自定义字体和颜色。
|
79 |
|
80 |
+
## [9/18] 程序摘要: toolbox.py
|
81 |
|
82 |
+
该程序文件包含了一系列函数,用于实现聊天程序所需的各种功能,如预测对话、将对话记录写入文件、将普通文本转换为Markdown格式文本、装饰器函数CatchException和HotReload等。其中一些函数用到了第三方库,如Python-Markdown、mdtex2html、zipfile、tarfile、rarfile和py7zr。除此之外,还有一些辅助函数,如get_conf、clear_line_break和extract_archive等。主要功能包括:
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
84 |
1. 导入markdown、mdtex2html、threading、functools等模块。
|
85 |
2. 定义函数predict_no_ui_but_counting_down,用于生成对话。
|
|
|
96 |
13. 定义函数on_file_uploaded,用于处理上传文件的操作。
|
97 |
14. 定义函数on_report_generated,用于处理生成报告文件的操作。
|
98 |
|
|
|
99 |
|
100 |
+
## [10/18] 程序摘要: crazy_functions/生成函数注释.py
|
101 |
+
|
102 |
+
该程序文件是一个Python脚本,文件名为“生成函数注释.py”,位于“./crazy_functions/”目录下。该程序实现了一个批量生成函数注释的功能,可以对指定文件夹下的所有Python和C++源代码文件中的所有函数进行注释,使用Markdown表格输出注释结果。
|
103 |
+
|
104 |
+
该程序引用了predict.py和toolbox.py两个模块,其中predict.py实现了一个基于GPT模型的文本生成功能,用于生成函数注释,而toolbox.py实现了一些工具函数,包括异常处理函数、文本写入函数等。另外,该程序还定义了两个函数,一个是“生成函数注释”函数,用于处理单个文件的注释生成;另一个是“批量生成函数注释”函数,用于批量处理多个文件的注释生成。
|
105 |
+
|
106 |
+
## [11/18] 程序摘要: crazy_functions/读文章写摘要.py
|
107 |
+
|
108 |
+
这个程序文件是一个名为“读文章写摘要”的函数。该函数的输入包括文章的文本内容、top_p(生成文本时选择最可能的词语的概率阈值)、temperature(控制生成文本的随机性的因子)、对话历史等参数,以及一个聊天机器人和一个系统提示的文本。该函数的主要工作是解析一组.tex文件,然后生成一段学术性语言的中文和英文摘要。在解析过程中,该函数使用一个名为“toolbox”的模块中的辅助函数和一个名为“predict”的模块中的函数来执行GPT-2模型的推理工作,然后将结果返回给聊天机器人。另外,该程序还包括一个名为“fast_debug”的bool型变量,用于调试和测试。
|
109 |
+
|
110 |
+
## [12/18] 程序摘要: crazy_functions/代码重写为全英文_多线程.py
|
111 |
+
|
112 |
+
该程序文件实现了一个多线程操作,用于将指定目录下的所有 Python 文件中的中文转化为英文,并将转化后的文件存入另一个目录中。具体实现过程如下:
|
113 |
+
|
114 |
+
1. 集合目标文件路径并清空历史记录。
|
115 |
+
2. 循环目标文件,对每个文件启动一个线程进行任务操作。
|
116 |
+
3. 各个线程同时开始执行任务函数,并在任务完成后将转化后的文件写入指定目录,最终生成一份任务执行报告。
|
117 |
+
|
118 |
+
## [13/18] 程序摘要: crazy_functions/高级功能函数模板.py
|
119 |
+
|
120 |
+
该程序文件名为高级功能函数模板.py,它包含了一个名为“高阶功能模板函数”的函数,这个函数可以作为开发新功能函数的模板。该函数引用了predict.py和toolbox.py文件中的函数。在该函数内部,它首先清空了历史记录,然后对于今天和今天以后的四天,它问用户历史中哪些事件发生在这些日期,并列举两条事件并发送相关的图片。在向用户询问问题时,使用了GPT进行响应。由于请求GPT需要一定的时间,所以函数会在重新显示状态之前等待一段时间。在每次与用户的互动中,使用yield关键字生成器函数来输出聊天机器人的当前状态,包括聊天消息、历史记录和状态('正常')。最后,程序调用write_results_to_file函数将聊天的结果写入文件,以供后续的评估和分析。
|
121 |
+
|
122 |
+
## [14/18] 程序摘要: crazy_functions/总结word文档.py
|
123 |
+
|
124 |
+
该程序文件名为总结word文档.py,主要功能是批量总结Word文档。具体实现过程是解析docx格式和doc格式文件,生成文件内容,然后使用自然语言处理工具对文章内容做中英文概述,最后给出建议。该程序需要依赖python-docx和pywin32,如果没有安装,会给出安装建议。
|
125 |
+
|
126 |
+
## [15/18] 程序摘要: crazy_functions/批量总结PDF文档pdfminer.py
|
127 |
+
|
128 |
+
该程序文件名为pdfminer.py,位于./crazy_functions/目录下。程序实现了批量读取PDF文件,并使用pdfminer解析PDF文件内容。此外,程序还根据解析得到的文本内容,调用机器学习模型生成对每篇文章的概述,最终生成全文摘要。程序中还对模块依赖进行了导入检查,若缺少依赖,则会提供安装建议。
|
129 |
+
|
130 |
+
## [16/18] 程序摘要: crazy_functions/解析项目源代码.py
|
131 |
+
|
132 |
+
这个程序文件中包含了几个函数,分别是:
|
133 |
+
|
134 |
+
1. `解析源代码(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)`:通过输入文件路径列表对程序文件进行逐文件分析,根据分析结果做出整体功能和构架的概括,并生成包括每个文件功能的markdown表格。
|
135 |
+
2. `解析项目本身(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)`:对当前文���夹下的所有Python文件及其子文件夹进行逐文件分析,并生成markdown表格。
|
136 |
+
3. `解析一个Python项目(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)`:对指定路径下的所有Python文件及其子文件夹进行逐文件分析,并生成markdown表格。
|
137 |
+
4. `解析一个C项目的头文件(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)`:对指定路径下的所有头文件进行逐文件分析,并生成markdown表格。
|
138 |
+
5. `解析一个C项目(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)`:对指定路径下的所有.h、.cpp、.c文件及其子文件夹进行逐文件分析,并生成markdown表格。
|
139 |
+
|
140 |
+
程序中还包含了一些辅助函数和变量,如CatchException装饰器函数,report_execption函数、write_results_to_file函数等。在执行过程中还会调用其他模块中的函数,如toolbox模块的函数和predict模块的函数。
|
141 |
+
|
142 |
+
## [17/18] 程序摘要: crazy_functions/批量总结PDF文档.py
|
143 |
+
|
144 |
+
这个程序文件是一个名为“批量总结PDF文档”的函数插件。它导入了predict和toolbox模块,并定义了一些函数,包括is_paragraph_break,normalize_text和clean_text。这些函数是对输入文本进行预处理和清洗的功能函数。主要的功能函数是解析PDF,它打开每个PDF文件并将其内容存储在file_content变量中,然后传递给聊天机器人,以产生一句话的概括。在解析PDF文件之后,该函数连接了所有文件的摘要,以产生一段学术语言和英文摘要。最后,函数批量处理目标文件夹中的所有PDF文件,并输出结果。
|
145 |
+
|
146 |
+
## 根据以上你自己的分析,对程序的整体功能和构架做出概括。然后用一张markdown表格整理每个文件的功能。
|
147 |
+
|
148 |
+
该程序是一个聊天机器人,使用了OpenAI的GPT语言模型以及一些特殊的辅助功能去处理各种学术写作和科研润色任务。整个程序由一些函数组成,每个函数都代表了不同的学术润色/翻译/其他服务。
|
149 |
|
150 |
+
下面是程序中每个文件的功能列表:
|
151 |
|
152 |
+
| 文件名 | 功能 |
|
153 |
+
|--------|--------|
|
154 |
+
| functional_crazy.py | 实现高级功能函数模板和其他一些辅助功能函数 |
|
155 |
+
| main.py | 程序的主要入口,负责程序的启动和UI的展示 |
|
156 |
+
| functional.py | 定义各种功能按钮的颜色和响应函数 |
|
157 |
+
| show_math.py | 解析LaTeX文本,将其转换为Markdown格式 |
|
158 |
+
| predict.py | 基础的对话功能,用于与chatGPT进行交互 |
|
159 |
+
| check_proxy.py | 检查代理设置的正确性 |
|
160 |
+
| config_private.py | 配置程序的API密钥和其他私有信息 |
|
161 |
+
| config.py | 配置OpenAI的API参数和程序的其他属性 |
|
162 |
+
| theme.py | 设置程序主题样式 |
|
163 |
+
| toolbox.py | 存放一些辅助函数供程序使用 |
|
164 |
+
| crazy_functions/生成函数注释.py | 生成Python文件中所有函数的注释 |
|
165 |
+
| crazy_functions/读文章写摘要.py | 解析文章文本,生成中英文摘要 |
|
166 |
+
| crazy_functions/代码重写为全英文_多线程.py | 将中文代码内容转化为英文 |
|
167 |
+
| crazy_functions/高级功能函数模板.py | 实现高级功能函数模板 |
|
168 |
+
| crazy_functions/总结word文档.py | 解析Word文件,生成文章内容的概要 |
|
169 |
+
| crazy_functions/批量总结PDF文档pdfminer.py | 解析PDF文件,生成文章内容的概要(使用pdfminer库) |
|
170 |
+
| crazy_functions/批量总结PDF文档.py | 解析PDF文件,生成文章内容的概要(使用PyMuPDF库) |
|
171 |
+
| crazy_functions/解析项目源代码.py | 解析C/C++源代码,生成markdown表格 |
|
172 |
+
| crazy_functions/批量总结PDF文档.py | 对PDF文件进行批量摘要生成 |
|
173 |
|
174 |
+
总的来说,该程序提供了一系列的学术润色和翻译的工具,支持对各种类型的文件进行分析和处理。同时也提供了对话式用户界面,便于用户使用和交互。
|
175 |
|
requirements.txt
CHANGED
@@ -1,3 +1,5 @@
|
|
1 |
gradio>=3.23
|
2 |
requests[socks]
|
3 |
mdtex2html
|
|
|
|
|
|
1 |
gradio>=3.23
|
2 |
requests[socks]
|
3 |
mdtex2html
|
4 |
+
Markdown
|
5 |
+
latex2mathml
|
theme.py
CHANGED
@@ -80,3 +80,15 @@ def adjust_theme():
|
|
80 |
except:
|
81 |
set_theme = None; print('gradio版本较旧, 不能自定义字体和颜色')
|
82 |
return set_theme
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
except:
|
81 |
set_theme = None; print('gradio版本较旧, 不能自定义字体和颜色')
|
82 |
return set_theme
|
83 |
+
|
84 |
+
advanced_css = """
|
85 |
+
.markdown-body table {
|
86 |
+
border: 1px solid #ddd;
|
87 |
+
border-collapse: collapse;
|
88 |
+
}
|
89 |
+
|
90 |
+
.markdown-body th, .markdown-body td {
|
91 |
+
border: 1px solid #ddd;
|
92 |
+
padding: 5px;
|
93 |
+
}
|
94 |
+
"""
|
toolbox.py
CHANGED
@@ -1,13 +1,34 @@
|
|
1 |
-
import markdown, mdtex2html, threading, importlib, traceback
|
2 |
from show_math import convert as convert_math
|
3 |
-
from functools import wraps
|
4 |
|
5 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
"""
|
7 |
调用简单的predict_no_ui接口,但是依然保留了些许界面心跳功能,当对话太长时,会自动采用二分法截断
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
"""
|
9 |
import time
|
10 |
-
from predict import predict_no_ui
|
11 |
from toolbox import get_conf
|
12 |
TIMEOUT_SECONDS, MAX_RETRY = get_conf('TIMEOUT_SECONDS', 'MAX_RETRY')
|
13 |
# 多线程的时候,需要一个mutable结构在不同线程之间传递信息
|
@@ -17,18 +38,25 @@ def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temp
|
|
17 |
def mt(i_say, history):
|
18 |
while True:
|
19 |
try:
|
20 |
-
|
|
|
|
|
|
|
21 |
break
|
22 |
-
except ConnectionAbortedError as
|
|
|
|
|
23 |
if len(history) > 0:
|
24 |
-
history = [his[len(his)
|
25 |
-
mutable[1] = 'Warning! History conversation is too long, cut into half. '
|
26 |
else:
|
27 |
-
i_say = i_say[:len(i_say)
|
28 |
-
|
29 |
except TimeoutError as e:
|
30 |
-
mutable[0] = '[Local Message]
|
31 |
raise TimeoutError
|
|
|
|
|
|
|
32 |
# 创建新线程发出http请求
|
33 |
thread_name = threading.Thread(target=mt, args=(i_say, history)); thread_name.start()
|
34 |
# 原来的线程则负责持续更新UI,实现一个超时倒计时,并等待新线程的任务完成
|
@@ -92,6 +120,17 @@ def CatchException(f):
|
|
92 |
yield chatbot, history, f'异常 {e}'
|
93 |
return decorated
|
94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
def report_execption(chatbot, history, a, b):
|
96 |
"""
|
97 |
向chatbot中添加错误信息
|
@@ -118,11 +157,12 @@ def markdown_convertion(txt):
|
|
118 |
"""
|
119 |
将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。
|
120 |
"""
|
|
|
|
|
121 |
if ('$' in txt) and ('```' not in txt):
|
122 |
-
return markdown.markdown(txt,extensions=['fenced_code','tables']) + '<br><br>' +
|
123 |
-
markdown.markdown(convert_math(txt, splitParagraphs=False),extensions=['fenced_code','tables'])
|
124 |
else:
|
125 |
-
return markdown.markdown(txt,extensions=['fenced_code','tables'])
|
126 |
|
127 |
|
128 |
def format_io(self, y):
|
@@ -168,8 +208,32 @@ def extract_archive(file_path, dest_dir):
|
|
168 |
with tarfile.open(file_path, 'r:*') as tarobj:
|
169 |
tarobj.extractall(path=dest_dir)
|
170 |
print("Successfully extracted tar archive to {}".format(dest_dir))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
else:
|
172 |
-
return
|
|
|
173 |
|
174 |
def find_recent_files(directory):
|
175 |
"""
|
@@ -201,16 +265,19 @@ def on_file_uploaded(files, chatbot, txt):
|
|
201 |
except: pass
|
202 |
time_tag = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
203 |
os.makedirs(f'private_upload/{time_tag}', exist_ok=True)
|
|
|
204 |
for file in files:
|
205 |
file_origin_name = os.path.basename(file.orig_name)
|
206 |
shutil.copy(file.name, f'private_upload/{time_tag}/{file_origin_name}')
|
207 |
-
extract_archive(f'private_upload/{time_tag}/{file_origin_name}',
|
208 |
dest_dir=f'private_upload/{time_tag}/{file_origin_name}.extract')
|
209 |
moved_files = [fp for fp in glob.glob('private_upload/**/*', recursive=True)]
|
210 |
txt = f'private_upload/{time_tag}'
|
211 |
moved_files_str = '\t\n\n'.join(moved_files)
|
212 |
-
chatbot.append(['我上传了文件,请查收',
|
213 |
-
f'[Local Message] 收到以下文件: \n\n{moved_files_str}
|
|
|
|
|
214 |
return chatbot, txt
|
215 |
|
216 |
|
@@ -219,24 +286,40 @@ def on_report_generated(files, chatbot):
|
|
219 |
report_files = find_recent_files('gpt_log')
|
220 |
if len(report_files) == 0: return report_files, chatbot
|
221 |
# files.extend(report_files)
|
222 |
-
chatbot.append(['汇总报告如何远程获取?', '
|
223 |
return report_files, chatbot
|
224 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
def get_conf(*args):
|
226 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
227 |
res = []
|
228 |
for arg in args:
|
229 |
-
|
230 |
-
except: r = getattr(importlib.import_module('config'), arg)
|
231 |
res.append(r)
|
232 |
-
# 在读取API_KEY时,检查一下是不是忘了改config
|
233 |
-
if arg=='API_KEY' and len(r) != 51:
|
234 |
-
assert False, "正确的API_KEY密钥是51位,请在config文件中修改API密钥, 添加海外代理之后再运行。" + \
|
235 |
-
"(如果您刚更新过代码,请确保旧版config_private文件中没有遗留任何新增键值)"
|
236 |
return res
|
237 |
|
238 |
def clear_line_break(txt):
|
239 |
txt = txt.replace('\n', ' ')
|
240 |
txt = txt.replace(' ', ' ')
|
241 |
txt = txt.replace(' ', ' ')
|
242 |
-
return txt
|
|
|
1 |
+
import markdown, mdtex2html, threading, importlib, traceback, importlib, inspect, re
|
2 |
from show_math import convert as convert_math
|
3 |
+
from functools import wraps, lru_cache
|
4 |
|
5 |
+
def get_reduce_token_percent(text):
|
6 |
+
try:
|
7 |
+
# text = "maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens"
|
8 |
+
pattern = r"(\d+)\s+tokens\b"
|
9 |
+
match = re.findall(pattern, text)
|
10 |
+
EXCEED_ALLO = 500 # 稍微留一点余地,否则在回复时会因余量太少出问题
|
11 |
+
max_limit = float(match[0]) - EXCEED_ALLO
|
12 |
+
current_tokens = float(match[1])
|
13 |
+
ratio = max_limit/current_tokens
|
14 |
+
assert ratio > 0 and ratio < 1
|
15 |
+
return ratio, str(int(current_tokens-max_limit))
|
16 |
+
except:
|
17 |
+
return 0.5, '不详'
|
18 |
+
|
19 |
+
def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, top_p, temperature, history=[], sys_prompt='', long_connection=True):
|
20 |
"""
|
21 |
调用简单的predict_no_ui接口,但是依然保留了些许界面心跳功能,当对话太长时,会自动采用二分法截断
|
22 |
+
i_say: 当前输入
|
23 |
+
i_say_show_user: 显示到对话界面上的当前输入,例如,输入整个文件时,你绝对不想把文件的内容都糊到对话界面上
|
24 |
+
chatbot: 对话界面句柄
|
25 |
+
top_p, temperature: gpt参数
|
26 |
+
history: gpt参数 对话历史
|
27 |
+
sys_prompt: gpt参数 sys_prompt
|
28 |
+
long_connection: 是否采用更稳定的连接方式(推荐)
|
29 |
"""
|
30 |
import time
|
31 |
+
from predict import predict_no_ui, predict_no_ui_long_connection
|
32 |
from toolbox import get_conf
|
33 |
TIMEOUT_SECONDS, MAX_RETRY = get_conf('TIMEOUT_SECONDS', 'MAX_RETRY')
|
34 |
# 多线程的时候,需要一个mutable结构在不同线程之间传递信息
|
|
|
38 |
def mt(i_say, history):
|
39 |
while True:
|
40 |
try:
|
41 |
+
if long_connection:
|
42 |
+
mutable[0] = predict_no_ui_long_connection(inputs=i_say, top_p=top_p, temperature=temperature, history=history, sys_prompt=sys_prompt)
|
43 |
+
else:
|
44 |
+
mutable[0] = predict_no_ui(inputs=i_say, top_p=top_p, temperature=temperature, history=history, sys_prompt=sys_prompt)
|
45 |
break
|
46 |
+
except ConnectionAbortedError as token_exceeded_error:
|
47 |
+
# 尝试计算比例,尽可能多地保留文本
|
48 |
+
p_ratio, n_exceed = get_reduce_token_percent(str(token_exceeded_error))
|
49 |
if len(history) > 0:
|
50 |
+
history = [his[ int(len(his) *p_ratio): ] for his in history if his is not None]
|
|
|
51 |
else:
|
52 |
+
i_say = i_say[: int(len(i_say) *p_ratio) ]
|
53 |
+
mutable[1] = f'警告,文本过长将进行截断,Token溢出数:{n_exceed},截断比例:{(1-p_ratio):.0%}。'
|
54 |
except TimeoutError as e:
|
55 |
+
mutable[0] = '[Local Message] 请求超时。'
|
56 |
raise TimeoutError
|
57 |
+
except Exception as e:
|
58 |
+
mutable[0] = f'[Local Message] 异常:{str(e)}.'
|
59 |
+
raise RuntimeError(f'[Local Message] 异常:{str(e)}.')
|
60 |
# 创建新线程发出http请求
|
61 |
thread_name = threading.Thread(target=mt, args=(i_say, history)); thread_name.start()
|
62 |
# 原来的线程则负责持续更新UI,实现一个超时倒计时,并等待新线程的任务完成
|
|
|
120 |
yield chatbot, history, f'异常 {e}'
|
121 |
return decorated
|
122 |
|
123 |
+
def HotReload(f):
|
124 |
+
"""
|
125 |
+
装饰器函数,实现函数插件热更新
|
126 |
+
"""
|
127 |
+
@wraps(f)
|
128 |
+
def decorated(*args, **kwargs):
|
129 |
+
fn_name = f.__name__
|
130 |
+
f_hot_reload = getattr(importlib.reload(inspect.getmodule(f)), fn_name)
|
131 |
+
yield from f_hot_reload(*args, **kwargs)
|
132 |
+
return decorated
|
133 |
+
|
134 |
def report_execption(chatbot, history, a, b):
|
135 |
"""
|
136 |
向chatbot中添加错误信息
|
|
|
157 |
"""
|
158 |
将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。
|
159 |
"""
|
160 |
+
pre = '<div class="markdown-body">'
|
161 |
+
suf = '</div>'
|
162 |
if ('$' in txt) and ('```' not in txt):
|
163 |
+
return pre + markdown.markdown(txt,extensions=['fenced_code','tables']) + '<br><br>' + markdown.markdown(convert_math(txt, splitParagraphs=False),extensions=['fenced_code','tables']) + suf
|
|
|
164 |
else:
|
165 |
+
return pre + markdown.markdown(txt,extensions=['fenced_code','tables']) + suf
|
166 |
|
167 |
|
168 |
def format_io(self, y):
|
|
|
208 |
with tarfile.open(file_path, 'r:*') as tarobj:
|
209 |
tarobj.extractall(path=dest_dir)
|
210 |
print("Successfully extracted tar archive to {}".format(dest_dir))
|
211 |
+
|
212 |
+
# 第三方库,需要预先pip install rarfile
|
213 |
+
# 此外,Windows上还需要安装winrar软件,配置其Path环境变量,如"C:\Program Files\WinRAR"才可以
|
214 |
+
elif file_extension == '.rar':
|
215 |
+
try:
|
216 |
+
import rarfile
|
217 |
+
with rarfile.RarFile(file_path) as rf:
|
218 |
+
rf.extractall(path=dest_dir)
|
219 |
+
print("Successfully extracted rar archive to {}".format(dest_dir))
|
220 |
+
except:
|
221 |
+
print("Rar format requires additional dependencies to install")
|
222 |
+
return '\n\n需要安装pip install rarfile来解压rar文件'
|
223 |
+
|
224 |
+
# 第三方库,需要预先pip install py7zr
|
225 |
+
elif file_extension == '.7z':
|
226 |
+
try:
|
227 |
+
import py7zr
|
228 |
+
with py7zr.SevenZipFile(file_path, mode='r') as f:
|
229 |
+
f.extractall(path=dest_dir)
|
230 |
+
print("Successfully extracted 7z archive to {}".format(dest_dir))
|
231 |
+
except:
|
232 |
+
print("7z format requires additional dependencies to install")
|
233 |
+
return '\n\n需要安装pip install py7zr来解压7z文件'
|
234 |
else:
|
235 |
+
return ''
|
236 |
+
return ''
|
237 |
|
238 |
def find_recent_files(directory):
|
239 |
"""
|
|
|
265 |
except: pass
|
266 |
time_tag = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
267 |
os.makedirs(f'private_upload/{time_tag}', exist_ok=True)
|
268 |
+
err_msg = ''
|
269 |
for file in files:
|
270 |
file_origin_name = os.path.basename(file.orig_name)
|
271 |
shutil.copy(file.name, f'private_upload/{time_tag}/{file_origin_name}')
|
272 |
+
err_msg += extract_archive(f'private_upload/{time_tag}/{file_origin_name}',
|
273 |
dest_dir=f'private_upload/{time_tag}/{file_origin_name}.extract')
|
274 |
moved_files = [fp for fp in glob.glob('private_upload/**/*', recursive=True)]
|
275 |
txt = f'private_upload/{time_tag}'
|
276 |
moved_files_str = '\t\n\n'.join(moved_files)
|
277 |
+
chatbot.append(['我上传了文件,请查收',
|
278 |
+
f'[Local Message] 收到以下文件: \n\n{moved_files_str}'+
|
279 |
+
f'\n\n调用路径参数已自动修正到: \n\n{txt}'+
|
280 |
+
f'\n\n现在您点击任意实验功能时,以上文件将被作为输入参数'+err_msg])
|
281 |
return chatbot, txt
|
282 |
|
283 |
|
|
|
286 |
report_files = find_recent_files('gpt_log')
|
287 |
if len(report_files) == 0: return report_files, chatbot
|
288 |
# files.extend(report_files)
|
289 |
+
chatbot.append(['汇总报告如何远程获取?', '汇总报告已经添加到右侧“文件上传区”(可能处于折叠状态),请查收。'])
|
290 |
return report_files, chatbot
|
291 |
|
292 |
+
@lru_cache
|
293 |
+
def read_single_conf_with_lru_cache(arg):
|
294 |
+
try: r = getattr(importlib.import_module('config_private'), arg)
|
295 |
+
except: r = getattr(importlib.import_module('config'), arg)
|
296 |
+
# 在读取API_KEY时,检查一下是不是忘了改config
|
297 |
+
if arg=='API_KEY':
|
298 |
+
# 正确的 API_KEY 是 "sk-" + 48 位大小写字母数字的组合
|
299 |
+
API_MATCH = re.match(r"sk-[a-zA-Z0-9]{48}$", r)
|
300 |
+
if API_MATCH:
|
301 |
+
print(f"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功")
|
302 |
+
else:
|
303 |
+
assert False, "正确的 API_KEY 是 'sk-' + '48 位大小写字母数字' 的组合,请在config文件中修改API密钥, 添加海外代理之后再运行。" + \
|
304 |
+
"(如果您刚更新过代码,请确保旧版config_private文件中没有遗留任何新增键值)"
|
305 |
+
if arg=='proxies':
|
306 |
+
if r is None:
|
307 |
+
print('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问。建议:检查USE_PROXY选项是否修改。')
|
308 |
+
else:
|
309 |
+
print('[PROXY] 网络代理状态:已配置。配置信息如下:', r)
|
310 |
+
assert isinstance(r, dict), 'proxies格式错误,请注意proxies选项的格式,不要遗漏括号。'
|
311 |
+
return r
|
312 |
+
|
313 |
def get_conf(*args):
|
314 |
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
315 |
res = []
|
316 |
for arg in args:
|
317 |
+
r = read_single_conf_with_lru_cache(arg)
|
|
|
318 |
res.append(r)
|
|
|
|
|
|
|
|
|
319 |
return res
|
320 |
|
321 |
def clear_line_break(txt):
|
322 |
txt = txt.replace('\n', ' ')
|
323 |
txt = txt.replace(' ', ' ')
|
324 |
txt = txt.replace(' ', ' ')
|
325 |
+
return txt
|