Skip to content

Instantly share code, notes, and snippets.

@mieki256
Created November 10, 2015 11:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mieki256/bdbfc754f846e85828b7 to your computer and use it in GitHub Desktop.
Save mieki256/bdbfc754f846e85828b7 to your computer and use it in GitHub Desktop.
fakeantijaggies2.py - アンチジャギのテスト
#!/usr/bin/env python
# -*- mode: python; Encoding: utf-8; coding: utf-8 -*-
# Last updated: <2015/11/10 02:24:47 +0900>
"""
fakeantijaggies2
アンチジャギ、ジャギ消しの実験。
layman, lrevise.c を移植。
たぶん移植時に失敗して動作がバグってる予感。
original 佐藤 正春
移植 mieki256
usage:
python fakeantijaggies2.py -i INPUT.png -o OUT.png
use: Python 2.7.10 + Pillow
"""
__version__ = '0.0.1'
from optparse import OptionParser, OptionValueError
from PIL import Image
import sys
import os
def c_set(img, x1, y1, x2, y2, f, dbgimg, dbgcol):
u"""
ドットを打つ。
x1, y1 参照座標
x2, y2 描画座標
f 参照色割合 ( / 128)
dbgcol デバッグ用指定職
"""
if not dbgimg is None:
dbgimg.putpixel((x2, y2), dbgcol)
# 割合が0以下なら何もしない
if f <= 0:
return
r0, g0, b0, a0 = img.getpixel((x1, y1))
r1, g1, b1, a1 = img.getpixel((x2, y2))
# 参照座標と描画座標が同じ色なら何もしない
if r0 == r1 and g0 == g1 and b0 == b1:
return
if f < 256:
# 割合が256未満なら描画すべきRGB値を求める
# 256以上なら参照座標のRGB値をそのまま使って描画
r0 = ((r0 * f) + (r1 * (256 - f)) + 128) >> 8
g0 = ((g0 * f) + (g1 * (256 - f)) + 128) >> 8
b0 = ((b0 * f) + (b1 * (256 - f)) + 128) >> 8
img.putpixel((x2, y2), (r0, g0, b0, a1))
def set_pixels(img, x, y, up, left, down, right, sw, fuz, dbgimg):
u"""指定された座標から上下左右にグラデーションを描画"""
if not dbgimg is None:
print "x,y=(%d,%d) up,left,down,right=(%d,%d,%d,%d) sw=%d" % \
(x, y, up, left, down, right, sw)
w, h = img.size
adj = 128
# x0, y0 : 描画座標 dst
# x1, y1 : 参照座標 src
# 上方向に描画
# O x -> S D x O -> D S
# x O x x O x x x
if not dbgimg is None:
dbgcol = (0, 0, 255, 255)
else:
dbgcol = None
if sw == 0:
x0, y0, x1, y1 = x + 1, y, x, y
else:
x0, y0, x1, y1 = x, y, x + 1, y
if up > 0:
# 複数のドットを打つ場合
l1 = (up + 1) / 2
if (y - l1 + 1) < 0:
l1 = y + 1
if l1 < 4:
adj_tmp = adj - 16 # 式に根拠なし、と書いてあった
else:
adj_tmp = adj
i = 0
while i <= l1:
f1 = adj_tmp - (adj_tmp * i / l1)
c_set(img, x1, y1, x0, y0, f1, dbgimg, dbgcol)
y0 -= 1
i += 1
elif up == 0:
# 1ドットだけ打つ場合
c_set(img, x1, y1, x0, y0, adj / 2, dbgimg, dbgcol)
# 下方向に描画
# O x -> x x x O -> x x
# x O D S O x S D
if not dbgimg is None:
dbgcol = (0, 255, 255, 255)
else:
dbgcol = None
if sw == 0:
x0, y0, x1, y1 = x, y + 1, x + 1, y + 1
else:
x0, y0, x1, y1 = x + 1, y + 1, x, y + 1
if down > 0:
l1 = (down + 1) / 2
if (y + l1) > (h - 1):
l1 = (h - 1) - y
if l1 < 4:
adj_tmp = adj - 16
else:
adj_tmp = adj
i = 0
while i <= l1:
f1 = adj_tmp - (adj_tmp * i / l1)
c_set(img, x1, y1, x0, y0, f1, dbgimg, dbgcol)
y0 += 1
i += 1
elif down == 0:
c_set(img, x1, y1, x0, y0, adj / 2, dbgimg, dbgcol)
# 左方向に描画
# O x -> S x x O -> D x
# x O D x O x S x
if not dbgimg is None:
dbgcol = (0, 255, 0, 255)
else:
dbgcol = None
if sw == 0:
x0, y0, x1, y1 = x, y + 1, x, y
else:
x0, y0, x1, y1 = x, y, x, y + 1
if left > 0:
l1 = (left + 1) / 2
if (x - l1 + 1) < 0:
l1 = x + 1
if l1 < 4:
adj_tmp = adj - 16
else:
adj_tmp = adj
i = 0
while i <= l1:
f1 = adj_tmp - (adj_tmp * i / l1)
c_set(img, x1, y1, x0, y0, f1, dbgimg, dbgcol)
x0 -= 1
i += 1
elif left == 0:
# 上下描画ですでにドットが打たれてるはずなのでここでは何もしない
pass
# c_set(img, x1, y1, x0, y0, adj / 4, dbgimg, dbgcol)
# 右方向に描画
# O x -> x D x O -> x S
# x O x S O x x D
if not dbgimg is None:
dbgcol = (255, 0, 255, 255)
else:
dbgcol = None
if sw == 0:
x0, y0, x1, y1 = x + 1, y, x + 1, y + 1
else:
x0, y0, x1, y1 = x + 1, y + 1, x + 1, y
if right > 0:
l1 = (right + 1) / 2
if (x + l1) > (w - 1):
l1 = (w - 1) - x
if l1 < 4:
adj_tmp = adj - 16
else:
adj_tmp = adj
i = 0
while i <= l1:
f1 = adj_tmp - (adj_tmp * i / l1)
c_set(img, x1, y1, x0, y0, f1, dbgimg, dbgcol)
x0 += 1
i += 1
elif right == 0:
pass
# c_set(img, x1, y1, x0, y0, adj / 4, dbgimg, dbgcol)
def judge(img, x, y, sw, fuz, dbgimg):
u"""上下左右に連続部分がないか調べる。
sw = 0 なら右肩下がり
sw = 1 なら右肩上がり
"""
up, down, left, right = -1, -1, -1, -1
w, h = img.size
# 上方向に境界がどれだけ伸びているか調べる
if sw == 0:
x0, y0, x1, y1 = x, y, x + 1, y
else:
x0, y0, x1, y1 = x + 1, y, x, y
if not pix_equal(img, x0, y0, x1, y1, fuz):
# 隣の色が違うので境界部分
up = 0
m = 0
i = y - 1
while i >= 0:
m += 1
if pix_equal(img, x0, y0, x0, y0 - m, fuz) \
and not pix_equal(img, x0, y0, x1, y1 - m, fuz):
# 境界が続いている
up += 1
else:
break
i -= 1
# 左方向に境界がどれだけ伸びているか調べる
if sw == 0:
x0, y0, x1, y1 = x, y, x, y + 1
else:
x0, y0, x1, y1 = x, y + 1, x, y
if not pix_equal(img, x0, y0, x1, y1, fuz):
# 上下の色が違うので境界部分
left = 0
m = 0
i = x - 1
while i >= 0:
m += 1
if pix_equal(img, x0, y0, x0 - m, y0, fuz) \
and not pix_equal(img, x0, y0, x1 - m, y1, fuz):
left += 1
else:
break
i -= 1
# 下方向に境界がどれだけ伸びているか調べる
if sw == 0:
x0, y0, x1, y1 = x + 1, y + 1, x, y + 1
else:
x0, y0, x1, y1 = x, y + 1, x + 1, y + 1
if not pix_equal(img, x0, y0, x1, y1, fuz):
# 隣の色が違うので境界部分
down = 0
m = 0
i = y + 2
while i <= h - 1:
m += 1
if pix_equal(img, x0, y0, x0, y0 + m, fuz) \
and not pix_equal(img, x0, y0, x1, y1 + m, fuz):
# 境界が続いている
down += 1
else:
break
i += 1
# 右方向に境界がどれだけ伸びているか調べる
if sw == 0:
x0, y0, x1, y1 = x + 1, y + 1, x + 1, y
else:
x0, y0, x1, y1 = x + 1, y, x + 1, y + 1
if not pix_equal(img, x0, y0, x1, y1, fuz):
# 上下の色が違うので境界部分
right = 0
m = 0
i = x + 2
while i <= w - 1:
m += 1
if pix_equal(img, x0, y0, x0 + m, y0, fuz) \
and not pix_equal(img, x0, y0, x1 + m, y1, fuz):
right += 1
else:
break
i += 1
# グラデーションで塗る
if up >= 0 or left >= 0 or down >= 0 or right >= 0:
set_pixels(img, x, y, up, left, down, right, sw, fuz, dbgimg)
def pix_equal(img, x0, y0, x1, y1, fuz):
u"""指定座標の色を比較して結果をTrue/Falseで返す"""
r0, g0, b0, a0 = img.getpixel((x0, y0))
r1, g1, b1, a1 = img.getpixel((x1, y1))
if int(r0 / fuz) != int(r1 / fuz) \
or int(g0 / fuz) != int(g1 / fuz) \
or int(b0 / fuz) != int(b1 / fuz):
return False
return True
def main(imgfile, outfile, count, tcolor, fuz, debug):
# 画像を開く
img = Image.open(imgfile)
if img.mode != "RGBA":
img = img.convert("RGBA")
w, h = img.size
if debug:
dbgimg = Image.new("RGBA", (w, h))
else:
dbgimg = None
# 指定色で透明化
if tcolor is not None:
ttr, ttg, ttb = tcolor # transparent color
for y in xrange(h):
for x in xrange(w):
r, g, b, a = img.getpixel((x, y))
if r == ttr and g == ttg and b == ttb:
img.putpixel((x, y), (0, 0, 0, 0))
# ジャギ消し
for i in xrange(count):
for y in xrange(h - 1):
for x in xrange(w - 1):
# 2x2ドットが同色なら何もしない
if pix_equal(img, x, y, x + 1, y + 1, fuz) \
and pix_equal(img, x + 1, y, x, y + 1, fuz) \
and pix_equal(img, x, y, x, y + 1, fuz):
continue
# 右肩下がりで同色か
if pix_equal(img, x, y, x + 1, y + 1, fuz):
judge(img, x, y, 0, fuz, dbgimg)
# 右肩上がりで同色か
if pix_equal(img, x + 1, y, x, y + 1, fuz):
judge(img, x, y, 1, fuz, dbgimg)
img.save(outfile)
if debug:
root, ext = os.path.splitext(outfile)
dbgfile = "%s_dbg%s" % (root, ext)
dbgimg.save(dbgfile)
if __name__ == '__main__':
# コマンドラインオプションを判別
p = OptionParser(version=__version__)
p.add_option(
"-i", "--input", dest="imgfile", default=None, help="Input image file")
p.add_option(
"-o", "--output", dest="outfile", default=None, help="Output image file")
p.add_option(
"-c", "--count", type="int", dest="count", default=1, help="Count")
p.add_option(
"-f", type="int", dest="factor", default=4, help="Factor [4]")
p.add_option("-n", "--nottransparent", action="store_false",
dest="tp_fg", help="disable transparent")
p.add_option("-t", "--transparentcolor", dest="tcolor",
default="255,255,255", help="transparent color [255,255,255]")
p.add_option("--debug", action="store_true", default=False, help="debug")
opts, args = p.parse_args()
if opts.imgfile is None:
# 画像ファイルが指定されてないので、ヘルプを表示して終了
p.error("require Input image file")
p.print_help()
sys.exit
elif opts.outfile is None:
# 出力ファイルが指定されてないので生成
root, ext = os.path.splitext(opts.imgfile)
opts.outfile = "%s_new%s" % (root, ext)
if opts.tp_fg is False:
# 透明化をしない
tcol = None
else:
# 透明化したい指定色を取り出す
a = opts.tcolor.split(",")
tcol = (int(a[0]), int(a[1]), int(a[2]))
main(opts.imgfile, opts.outfile, opts.count, tcol, opts.factor, opts.debug)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment