image.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #!/usr/bin/env python
  2. import cStringIO
  3. import struct
  4. import os, os.path
  5. from pdftypes import LITERALS_DCT_DECODE
  6. from pdfcolor import LITERAL_DEVICE_GRAY, LITERAL_DEVICE_RGB, LITERAL_DEVICE_CMYK
  7. def align32(x):
  8. return ((x+3)//4)*4
  9. ## BMPWriter
  10. ##
  11. class BMPWriter(object):
  12. def __init__(self, fp, bits, width, height):
  13. self.fp = fp
  14. self.bits = bits
  15. self.width = width
  16. self.height = height
  17. if bits == 1:
  18. ncols = 2
  19. elif bits == 8:
  20. ncols = 256
  21. elif bits == 24:
  22. ncols = 0
  23. else:
  24. raise ValueError(bits)
  25. self.linesize = align32((self.width*self.bits+7)//8)
  26. self.datasize = self.linesize * self.height
  27. headersize = 14+40+ncols*4
  28. info = struct.pack('<IiiHHIIIIII', 40, self.width, self.height, 1, self.bits, 0, self.datasize, 0, 0, ncols, 0)
  29. assert len(info) == 40, len(info)
  30. header = struct.pack('<ccIHHI', 'B', 'M', headersize+self.datasize, 0, 0, headersize)
  31. assert len(header) == 14, len(header)
  32. self.fp.write(header)
  33. self.fp.write(info)
  34. if ncols == 2:
  35. # B&W color table
  36. for i in (0, 255):
  37. self.fp.write(struct.pack('BBBx', i, i, i))
  38. elif ncols == 256:
  39. # grayscale color table
  40. for i in xrange(256):
  41. self.fp.write(struct.pack('BBBx', i, i, i))
  42. self.pos0 = self.fp.tell()
  43. self.pos1 = self.pos0 + self.datasize
  44. return
  45. def write_line(self, y, data):
  46. self.fp.seek(self.pos1 - (y+1)*self.linesize)
  47. self.fp.write(data)
  48. return
  49. ## ImageWriter
  50. ##
  51. class ImageWriter(object):
  52. def __init__(self, outdir):
  53. self.outdir = outdir
  54. if not os.path.exists(self.outdir):
  55. os.makedirs(self.outdir)
  56. return
  57. def export_image(self, image):
  58. stream = image.stream
  59. filters = stream.get_filters()
  60. (width, height) = image.srcsize
  61. if len(filters) == 1 and filters[0] in LITERALS_DCT_DECODE:
  62. ext = '.jpg'
  63. elif (image.bits == 1 or
  64. image.bits == 8 and image.colorspace in (LITERAL_DEVICE_RGB, LITERAL_DEVICE_GRAY)):
  65. ext = '.%dx%d.bmp' % (width, height)
  66. else:
  67. ext = '.%d.%dx%d.img' % (image.bits, width, height)
  68. name = image.name+ext
  69. path = os.path.join(self.outdir, name)
  70. fp = file(path, 'wb')
  71. if ext == '.jpg':
  72. raw_data = stream.get_rawdata()
  73. if LITERAL_DEVICE_CMYK in image.colorspace:
  74. from PIL import Image
  75. from PIL import ImageChops
  76. ifp = cStringIO.StringIO(raw_data)
  77. i = Image.open(ifp)
  78. i = ImageChops.invert(i)
  79. i = i.convert('RGB')
  80. i.save(fp, 'JPEG')
  81. else:
  82. fp.write(raw_data)
  83. elif image.bits == 1:
  84. bmp = BMPWriter(fp, 1, width, height)
  85. data = stream.get_data()
  86. i = 0
  87. width = (width+7)//8
  88. for y in xrange(height):
  89. bmp.write_line(y, data[i:i+width])
  90. i += width
  91. elif image.bits == 8 and image.colorspace is LITERAL_DEVICE_RGB:
  92. bmp = BMPWriter(fp, 24, width, height)
  93. data = stream.get_data()
  94. i = 0
  95. width = width*3
  96. for y in xrange(height):
  97. bmp.write_line(y, data[i:i+width])
  98. i += width
  99. elif image.bits == 8 and image.colorspace is LITERAL_DEVICE_GRAY:
  100. bmp = BMPWriter(fp, 8, width, height)
  101. data = stream.get_data()
  102. i = 0
  103. for y in xrange(height):
  104. bmp.write_line(y, data[i:i+width])
  105. i += width
  106. else:
  107. fp.write(stream.get_data())
  108. fp.close()
  109. return name