diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..68bc17f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/README_cn.md b/README_cn.md index a2c7b520..a4cd08bf 100644 --- a/README_cn.md +++ b/README_cn.md @@ -166,6 +166,29 @@ WaterMark(..., processes=None) ``` - `processes`: 整数,指定线程数。默认为 `None`, 表示使用全部线程。 +# 在内存中操作 + +以下的 `bytes(...)` **仅作示意**,即需要传入 `bytes` 对象。 + +嵌入图片: +```python +from blind_watermark import WaterMark + +bwm1 = WaterMark(password_wm=1, password_img=1) +# 读取原始图 +bwm1.read_img(img=bytes(...)) +# 读取水印图 +bwm1.read_wm(bytes(...)) +# 嵌入 +bwm1.embed_bytes() +``` + +解水印:(注意设定水印形状 `wm_shape`) +```python +bwm1 = WaterMark(password_wm=1, password_img=1) +# wm_shape 是必要的 +bwm1.extract(embed_img=bytes(...), wm_shape=(128, 128)) +``` ## 相关项目 diff --git a/blind_watermark/blind_watermark.py b/blind_watermark/blind_watermark.py index 1eff8056..bf04b697 100644 --- a/blind_watermark/blind_watermark.py +++ b/blind_watermark/blind_watermark.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 # coding=utf-8 -# @Time : 2020/8/13 +# @Time : 2023/04/01 # @Author : github.com/guofei9987 +# @Author : github.com/jinzhijie import warnings import numpy as np @@ -28,14 +29,23 @@ def read_img(self, filename=None, img=None): img = cv2.imread(filename, flags=cv2.IMREAD_UNCHANGED) assert img is not None, "image file '{filename}' not read".format(filename=filename) + if isinstance(img, bytes): + # 读取 bytes 对象 + buf = np.frombuffer(img, np.uint8) + img = cv2.imdecode(buf, flags=cv2.IMREAD_UNCHANGED) + self.bwm_core.read_img_arr(img=img) return img def read_wm(self, wm_content, mode='img'): assert mode in ('img', 'str', 'bit'), "mode in ('img','str','bit')" if mode == 'img': - wm = cv2.imread(filename=wm_content, flags=cv2.IMREAD_GRAYSCALE) - assert wm is not None, 'file "{filename}" not read'.format(filename=wm_content) + if isinstance(wm_content, bytes): + buf = np.frombuffer(wm_content, dtype=np.uint8) + wm = cv2.imdecode(buf, flags=cv2.IMREAD_GRAYSCALE) + else: + wm = cv2.imread(filename=wm_content, flags=cv2.IMREAD_GRAYSCALE) + assert wm is not None, 'file "{filename}" not read'.format(filename=wm_content) # 读入图片格式的水印,并转为一维 bit 格式,抛弃灰度级别 self.wm_bit = wm.flatten() > 128 @@ -74,6 +84,10 @@ def embed(self, filename=None, compression_ratio=None): cv2.imwrite(filename=filename, img=embed_img) return embed_img + def embed_bytes(self, ext='.png'): + embed_img = self.bwm_core.embed() + return cv2.imencode(ext, embed_img)[1] + def extract_decrypt(self, wm_avg): wm_index = np.arange(self.wm_size) np.random.RandomState(self.password_wm).shuffle(wm_index) @@ -86,6 +100,10 @@ def extract(self, filename=None, embed_img=None, wm_shape=None, out_wm_name=None if filename is not None: embed_img = cv2.imread(filename, flags=cv2.IMREAD_COLOR) assert embed_img is not None, "{filename} not read".format(filename=filename) + + if isinstance(embed_img, bytes): + buf = np.frombuffer(embed_img, dtype=np.uint8) + embed_img = cv2.imdecode(buf, flags=cv2.IMREAD_COLOR) self.wm_size = np.array(wm_shape).prod() @@ -100,9 +118,10 @@ def extract(self, filename=None, embed_img=None, wm_shape=None, out_wm_name=None # 转化为指定格式: if mode == 'img': wm = 255 * wm.reshape(wm_shape[0], wm_shape[1]) - cv2.imwrite(out_wm_name, wm) + if out_wm_name is not None: + cv2.imwrite(out_wm_name, wm) elif mode == 'str': - byte = ''.join((np.round(wm)).astype(np.int).astype(np.str)) + byte = ''.join((np.round(wm)).astype(int).astype(str)) wm = bytes.fromhex(hex(int(byte, base=2))[2:]).decode('utf-8', errors='replace') return wm