2025年3月26日 星期三 甲辰(龙)年 月廿五 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

python 拼图问题 以及从swf文件导出图片

时间:11-12来源:作者:点击数:70
屏幕截图

首先生成了这个拼图,就是上面的那个图片的样子,然后我们可以看到有很多小碎片,而且是慢慢出现的,于是我就考虑是不是通过网络来请求的呢,于是用了chrome的审查元素,发现没有多与的http请求,于是我又想会不会是flash通过tcp请求来获得的呢,于是用了wireshark抓包,发现依然毫无所获,看来应该是图片都已经存储在flash文件里了。审查元素可以看到 http://three.flash-gear.com/npuz/puz.php?c=z&o=2&id=3986907&k=72291300&s=30&w=180&h=180&f_dm=three 这个请求的时间最长了,于是猜测这个应该是小碎片的flash文件,于是用下面的命令我们可以得到这个flash文件。

  • wget "http://three.flash-gear.com/npuz/puz.php?c=z&o=2&id=3986907&k=72291300&s=30&w=180&h=180&f_dm=three" -O test.swf

ok,文件得到了,打开看看吧,发现这个文件只是简单的把小碎片放到里面,用文本编辑器打开这个文件,发现里面有大量的“CREATOR: gd-jpeg v1.0 (using IJG JPEG v62)”这样的字样,这篇文章里有介绍swf的格式,和如何从swf文件取出图片,其实我们不用这么麻烦,既然图片都是直接包装在里面的,那么我们可以直接用正则取出图片。在这里可以看到jpeg头文件的相关说明。

  • import re
  • re_jpg = re.compile(r'(.{6}JFIF(.(?!(.{5}JFIF)))*)', re.M|re.S)
  • swf = open('test.swf', 'rb')
  • cnt = 0
  • for jpg in re_jpg.findall(swf.read()):
  • f = open('%d.jpg' % cnt, 'wb')
  • cnt += 1
  • f.write(jpg[0])
  • f.close()

运行程序我们便得到了所有的小碎片。

屏幕截图

这里我们用到了一个小trick,就是只要图片文件正确,我们向后面添加多余内容,不影响图片的正常解析,所以有的加密软件就是帮你把秘密添加到某个图片的后面,这样外表看上去是图片。

我们发现小图片竟然都是正方形的,而且竟然都是按照顺序给的,那么剩下的工作就很简单了,用PIL把图片拼起来就好了。注意PIL的(0,0)点是左上角,并且(x,y)是先第x列第y行的意思,这里经常容易出错。

  • from PIL import Image, ImageDraw
  • total = 36
  • row = 6
  • col = 6
  • w = 60
  • h = 60
  • im = Image.new('RGB', (w*col, h*row))
  • draw = ImageDraw.Draw(im)
  • for i in range(row):
  • for j in range(col):
  • now = Image.open('%d.jpg' % (i*col+j))
  • for x in range(h):
  • for y in range(w):
  • draw.point((j*h+x, i*w+y), now.getpixel((x, y)))
  • im.save('test.jpg')

图片生成后是这个样子

test1

很奇怪啊,我们再仔细观察发现原来图片是有重叠的,于是我们只要拿每张图片的右下角的1/4来组成就可以了,于是最后我们就完成了最后的拼图。

test

swf文件提取图片代码(python)

  • # Dump all JPEG tags from an SWF file
  • import os
  • import zlib
  • import struct
  • import StringIO
  • import Image
  • # Helpers for reading SWF files
  • def CalcMaskShift(pos, len):
  • shift = pos - len + 1
  • return (pow(2, len) - 1) << shift, shift
  • class BitStream(object):
  • lut = dict(((pos, len), CalcMaskShift(pos, len)) for pos in range(8) for len in range(1, pos+2))
  • def __init__(self, fp):
  • self.fp = fp
  • self.next()
  • def next(self):
  • c = self.fp.read(1)
  • if (c): self.curr_byte = ord(c)
  • else: self.curr_byte = None
  • self.bit_pos = 7
  • def tell(self):
  • return (self.fp.tell()-1, self.bit_pos)
  • def seek(self, curr_byte, bit_pos=7):
  • self.fp.seek(curr_byte)
  • self.next()
  • self.bit_pos = bit_pos
  • def align(self):
  • if (self.bit_pos != 7): self.next()
  • def make_signed(self, val, size):
  • flag = pow(2, size-1)
  • if (val >= flag):
  • return val - flag - flag
  • else:
  • return val
  • # Bit order is preserved; msb stored in msb
  • def read_partial_byte(self, size):
  • mask, shift = self.lut[(self.bit_pos, size)]
  • rv = (self.curr_byte & mask) >> shift
  • self.bit_pos = (self.bit_pos - size) & 0x7
  • if (self.bit_pos == 7): self.next()
  • return rv
  • # Bitfields are stored in MSB order
  • def read_bits(self, size, signedp):
  • # Segment read
  • head_len = min(size, self.bit_pos+1)
  • body_len = (size - head_len) / 8
  • tail_len = (size - head_len) & 0x7
  • # Perform read
  • rv = 0
  • if (head_len):
  • rv = self.read_partial_byte(head_len)
  • while (body_len):
  • rv = rv * 256 + self.curr_byte
  • self.next(); body_len -= 1
  • if (tail_len):
  • rv = (rv << tail_len) + self.read_partial_byte(tail_len)
  • if (signedp):
  • rv = self.make_signed(rv, size)
  • return rv
  • # Byte values are stored in LSB order
  • def read_bytes(self, size, signedp):
  • self.align(); rv = 0; factor = 1; nbits = size*8
  • while (size):
  • rv += (self.curr_byte*factor)
  • self.next(); factor *= 256; size -= 1
  • if (signedp):
  • rv = self.make_signed(rv, nbits)
  • return rv
  • def read_raw(self, size):
  • self.align()
  • data = chr(self.curr_byte) + self.fp.read(size-1)
  • self.next()
  • return data
  • # Low-level extraction code
  • def skip_bytes(bs, size):
  • byte_pos, bit_pos = bs.tell()
  • bs.seek(byte_pos+size)
  • def read_rect(bs):
  • nbits = bs.read_bits(5, False)
  • xmin = bs.read_bits(nbits, True)
  • xmax = bs.read_bits(nbits, True)
  • ymin = bs.read_bits(nbits, True)
  • ymax = bs.read_bits(nbits, True)
  • return (xmin, xmax, ymin, ymax)
  • def read_movie_header(bs):
  • rect = read_rect(bs)
  • fps = bs.read_bytes(2, False)/256.0
  • nframes = bs.read_bytes(2, False)
  • return ([n/20.0 for n in rect], fps, nframes)
  • def read_jpeg_table(bs, length):
  • # Strip the trailing end-of-stream
  • rv = bs.read_raw(length-2)
  • skip_bytes(bs, 2)
  • return rv
  • def read_jpeg_bits(bs, length, table):
  • # Get the bitmap ID
  • id = bs.read_bytes(2, False)
  • # Omit the opening beginning-of-stream
  • skip_bytes(bs, 2)
  • # Return a complete JPEG
  • return (id, table+bs.read_raw(length-4))
  • def read_jpeg_bits_2(bs, length):
  • # Contrary to documentation, this appears to consist of only a single
  • # JPEG stream - there is no FF D9 FF D8 quad in the datastream
  • id = bs.read_bytes(2, False)
  • return (id, bs.read_raw(length-2))
  • def read_jpeg_bits_3(bs, length):
  • # Most apps don't like SWF's two-stream-per-file business, so this
  • # crudely strips out the end-of-stream / start-of-stream tag pair.
  • # A little risky, but there's only a 2**-32 chance of it occuring randomly
  • id = bs.read_bytes(2, False)
  • jpg_len = bs.read_bytes(4, False)
  • img_data = bs.read_raw(jpg_len).replace('\xff\xd9\xff\xd8', '')
  • alpha_data = zlib.decompress(bs.read_raw(length-6-jpg_len))
  • return (id, img_data, alpha_data)
  • # Extraction utility fxn
  • def dump_jpegs(fn):
  • pn = os.path.split(fn)[0]
  • fp = file(fn, 'rb')
  • sig, ver, length = struct.unpack('<3sBL', fp.read(8))
  • if (sig == 'CWS'):
  • bs = BitStream(StringIO.StringIO(zlib.decompress(fp.read())))
  • elif (sig == 'FWS'):
  • bs = BitStream(fp)
  • else:
  • return
  • rect, fps, nframes = read_movie_header(bs)
  • print 'sig: ' + sig
  • print 'version: %d' % ver
  • print 'length: %d' % length
  • print 'screen: %.1fx%.1f' % (rect[1]-rect[0], rect[3]-rect[2])
  • print 'fps: %.1f' % fps
  • print 'num frames: %d' % nframes
  • table = None
  • while (1):
  • # Read tag header
  • code = bs.read_bytes(2, False)
  • tag = code >> 6
  • length = code & 0x3f
  • if (length == 63):
  • length = bs.read_bytes(4, False)
  • # Process JPEG tags, or skip
  • if (tag == 0):
  • break
  • elif (tag == 8):
  • table = read_jpeg_table(bs, length)
  • elif (tag == 6):
  • id, bits = read_jpeg_bits(bs, length, table)
  • file(os.path.join(pn, '%d.jpg'%id), 'wb').write(bits)
  • elif (tag == 21):
  • id, bits = read_jpeg_bits_2(bs, length)
  • file(os.path.join(pn, '%d.jpg'%id), 'wb').write(bits)
  • elif (tag == 35):
  • id, img_bits, alpha_bits = read_jpeg_bits_3(bs, length)
  • img = Image.open(StringIO.StringIO(img_bits)).convert('RGBA')
  • img.putalpha(Image.fromstring('L', img.size, alpha_bits))
  • img.save(os.path.join(pn, '%d.png'%id))
  • else:
  • skip_bytes(bs, length)

 

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门