Skip to content

Instantly share code, notes, and snippets.

@harjitmoe
Last active February 10, 2017 09:51
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 harjitmoe/d877966247098c37b5d1b6c209a5dac6 to your computer and use it in GitHub Desktop.
Save harjitmoe/d877966247098c37b5d1b6c209a5dac6 to your computer and use it in GitHub Desktop.
# Copyright (c) Secret Labs AB 1997-2003.
# Copyright (c) Fredrik Lundh 1995-2003.
#
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
#
# Permission to use, copy, modify, and distribute this software and its
# associated documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appears in all
# copies, and that both that copyright notice and this permission notice
# appear in supporting documentation, and that the name of Secret Labs
# AB or the author not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO
# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# To any copyright-eligible contributions by Thomas Hori (HarJIT),
# the following applies:
#
# Copyright (c) Thomas Hori.
# Contributions written 2012, 2015, 2016.
#
# THIS WORK IS PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL THE AUTHORS OR CONTRIBUTORS
# BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE),
# ARISING IN ANY WAY OUT OF THE USE OF THIS WORK, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Permission is granted to anyone to use this work for any purpose, including
# commercial applications, and to alter it and/or redistribute it freely in any
# form, with or without modification, subject to the following restrictions:
#
# 1. The origin of this work must not be misrepresented; you must not claim that
# you authored the original work. If you use this work in a product, an
# acknowledgment in the product documentation would be appreciated but is not
# required.
#
# 2. Altered versions in any form must not be misrepresented as being the
# original work, and neither the name of HarJIT nor the names of authors or
# contributors may be used to endorse or promote products derived from this
# work without specific prior written permission.
#
# 3. The text of this notice must be included, unaltered, with any distribution.
#
#
# The Python Imaging Library.
# $Id$
#
# Windows Icon support for PIL
#
# Notes:
# uses BmpImagePlugin.py to read the bitmap data.
#
# History:
# 1996-05-27 fl Created
# 2012-04-21 HarJIT <FORKED>
# 2012-04-21 HarJIT Added write code
# 2012-04-23 HarJIT Adjusted info header write code
# 2015-06-20 HarJIT Looked up about ico masks, fixes
# 2016-03-05 HarJIT Added mask generation.
#
# Write code by HarJIT derived from BmpImagePlugin.
# History of BmpImagePlugin:
# 1995-09-01 fl Created
# 1996-04-30 fl Added save
# 1997-08-27 fl Fixed save of 1-bit images
# 1998-03-06 fl Load P images as L where possible
# 1998-07-03 fl Load P images as 1 where possible
# 1998-12-29 fl Handle small palettes
# 2002-12-30 fl Fixed load of 1-bit palette images
# 2003-04-21 fl Fixed load of 1-bit monochrome images
# 2003-04-23 fl Added limited support for BI_BITFIELDS compression
#
__version__ = "0.1"
from PIL import Image, BmpImagePlugin
#
# --------------------------------------------------------------------
def i16(c):
return ord(c[0]) + (ord(c[1])<<8)
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix):
return prefix[:4] == "\0\0\1\0"
##
# Image plugin for Windows Icon files.
class IcoImageFile(BmpImagePlugin.BmpImageFile):
format = "ICO"
format_description = "Windows Icon"
def _open(self):
# check magic
s = self.fp.read(6)
if not _accept(s):
raise SyntaxError, "not an ICO file"
# pick the largest icon in the file
m = ""
for i in range(i16(s[4:])):
s = self.fp.read(16)
if not m:
m = s
elif ord(s[0]) > ord(m[0]) and ord(s[1]) > ord(m[1]):
m = s
print "width", ord(s[0])
print "height", ord(s[1])
print "colors", ord(s[2])
print "reserved", ord(s[3])
print "planes", i16(s[4:])
print "bitcount", i16(s[6:])
print "bytes", i32(s[8:])
print "offset", i32(s[12:])
# load as bitmap
self._bitmap(i32(m[12:]))
# patch up the bitmap height
self.size = self.size[0], self.size[1]/2
d, e, o, a = self.tile[0]
self.tile[0] = d, (0,0)+self.size, o, a
return
#
# --------------------------------------------------------------------
# Write ICO file
def genmask(i):
i=i.convert("RGBA")
width,height=i.size
j=Image.new("RGBA",(width,2*height))
k=Image.new("RGB",(width,height))
for x in range(width):
for y in range(height):
a=255-i.getpixel((x,y))[3]
k.putpixel((x,y),(a,a,a))
j.paste(k.convert("RGBA"),(0,0))
j.paste(i.convert("RGB").convert("RGBA"),(0,height))
return j
from PIL import ImageFile
def o16(i):
return chr(i&255) + chr(i>>8&255)
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
SAVE = {
# "1": ("1", 1, 2),
# "L": ("L", 8, 0),#256),
# "P": ("P", 8, 0),#256),
"RGB": ("BGR", 24, 0),
"RGBA": ("BGRA", 32, 0),
}
def SaveAsICO(ims, fp, filename=None, check=0):
if not hasattr(ims,"__len__"): #Quack typing
ims=(ims,)
for im in ims:
try:
rawmode, bits, colors = SAVE[im.mode]
except KeyError:
raise IOError("cannot write mode %s as ICO" % im.mode)
if check:
return check
ims=map(genmask,ims)
if not filename:
#fp could be *either* fp *or* (otherwise disused) filename here
try:
buffer(fp)
except TypeError:
pass
else:
fp=open(fp,"wb")
# ICO header
fp.write("\0\0" + # file type (magic)
o16(1) + # version (1=icon 2=cursor)
o16(len(ims))) # Number of images
# ICO directory
dirsize=len(ims)*16
running_offset=6+dirsize
for imno,im in enumerate(ims):
rawmode, bits, colors = SAVE[im.mode]
stride = ((im.size[0]*bits+7)/8+3)&(~3)
image = stride * im.size[1]
wid,hei = im.size
if wid>=256:
wid=0
if hei>=256:
hei=0
fp.write(chr(wid) + # width
chr(hei) + # height
chr(colors) + # colors used
"\0" + # reserved
o16(1) + # planes
o16(bits) + # BPP (depth)
o32(image) + # size of bitmap
o32(running_offset)) # offset of icon
running_offset+=image+40
# BMP info header (main BMP header must be absent)
for im in ims:
rawmode, bits, colors = SAVE[im.mode]
stride = ((im.size[0]*bits+7)/8+3)&(~3)
image = stride * im.size[1]
fp.write(o32(40) + # info header size
o32(im.size[0]) + # width
o32(im.size[1]) + # height including mask
o16(1) + # planes
o16(bits) + # depth (BPP)
o32(0) + # compression (0=uncompressed)
o32(image) + # size of bitmap
o32(1) + o32(1) + # resolution
o32(colors) + # colors used
o32(colors)) # colors important
if im.mode == "1":
for i in (0, 255):
fp.write(chr(i) * 4)
elif im.mode == "L":
for i in range(256):
fp.write(chr(i) * 4)
elif im.mode == "P":
fp.write(im.im.getpalette("RGB", "BGRX"))
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, stride, -1))])
#
# --------------------------------------------------------------------
Image.register_open("ICO", IcoImageFile, _accept)
Image.register_save("ICO", SaveAsICO)
Image.register_extension("ICO", ".ico")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment