PageRenderTime 40ms CodeModel.GetById 14ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/Hosts/MerlinWeb/examples/album.aspx.py

#
Python | 370 lines | 311 code | 28 blank | 31 comment | 38 complexity | 4083da9da5054b5c99d18df8e11a4fb2 MD5 | raw file
  1#  Copyright (c) Microsoft Corporation. 
  2#
  3#  This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  4#  copy of the license can be found in the License.html file at the root of this distribution. If 
  5#  you cannot locate the  Apache License, Version 2.0, please send an email to 
  6#  dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  7#  by the terms of the Apache License, Version 2.0.
  8#
  9#  You must not remove this notice, or any other, from this software.
 10
 11from System import DateTime, TimeSpan
 12from System.Drawing import Color, Bitmap, Graphics, Point, Rectangle, RectangleF, Pens, Brushes, Font
 13from System.Drawing.Drawing2D import InterpolationMode, LinearGradientBrush
 14from System.Drawing.Imaging import ImageFormat
 15from System.IO import Directory, File, Path, MemoryStream
 16from System.Web import HttpContext, HttpRuntime, HttpUtility
 17from System.Web.Caching import CacheDependency
 18from System.Web.Hosting import HostingEnvironment
 19
 20# Customization
 21
 22ThumbnailSize = 120
 23PreviewSize = 700
 24ChildFolderColor = Color.LightGray
 25ParentFolderColor = Color.LightSalmon
 26
 27# Helpers
 28
 29def BitmapToBytes(bitmap):
 30    ms = MemoryStream()
 31    bitmap.Save(ms, ImageFormat.Jpeg)
 32    ms.Close()
 33    return ms.ToArray()
 34
 35def GetCachedItem(itemType, path):
 36    cacheKey = 'py:albumitem:' + path
 37    # lookup in cache
 38    item = HttpRuntime.Cache.Get(cacheKey)
 39    if item is not None: return item
 40    # create new
 41    item = itemType(path)
 42    # cache it
 43    HttpRuntime.Cache.Insert(cacheKey, item, None, DateTime.MaxValue, TimeSpan.FromMinutes(4))
 44    return item
 45
 46# PICTURE respesents info about one picture
 47
 48class PICTURE:
 49    def __init__(self, filename):
 50        self.filename = filename
 51        self.name = Path.GetFileName(self.filename)
 52        self.__thumbnail = None
 53        self.__dims = None
 54
 55
 56    def __getDimensions(self):
 57        if self.__dims is None:
 58            origImage = Bitmap.FromFile(self.filename, False)
 59            self.__dims = (origImage.Width, origImage.Height)
 60            origImage.Dispose()
 61        return self.__dims
 62
 63    def CalcResizedDims(self, size):
 64        width, height = self.__getDimensions()
 65        if width >= height and width > size:
 66            return size, int(float(size*height)/width)
 67        elif height >= width and height > size:
 68            return int(float(size*width)/height), size
 69        else:
 70            return width, height
 71
 72    def DrawResizedImage(self, size):
 73        # load original image
 74        origImage = Bitmap.FromFile(self.filename, False)
 75        # calculate
 76        if self.__dims is None: self.__dims = (origImage.Width, origImage.Height)
 77        width, height = self.CalcResizedDims(size)
 78        # draw new image
 79        newImage = Bitmap(width, height)
 80        g = Graphics.FromImage(newImage)
 81        g.InterpolationMode = InterpolationMode.HighQualityBicubic
 82        g.DrawImage(origImage, 0, 0, width, height)
 83        imageBytes = BitmapToBytes(newImage)
 84        # cleanup
 85        g.Dispose()
 86        newImage.Dispose()
 87        origImage.Dispose()
 88        return imageBytes
 89
 90    def __drawPictureThumbnail(self):
 91        # load original image
 92        origImage = Bitmap.FromFile(self.filename, False)
 93        # calculate
 94        size = ThumbnailSize
 95        if self.__dims is None: self.__dims = (origImage.Width, origImage.Height)
 96        width, height = self.CalcResizedDims(size)
 97        drawWidth, drawHeight = width, height
 98        width, height = max(width, size), max(height, size)
 99        drawXOffset, drawYOffset = (width-drawWidth)/2, (height-drawHeight)/2
100        # draw new image
101        newImage = Bitmap(width, height)
102        g = Graphics.FromImage(newImage)
103        g.InterpolationMode = InterpolationMode.HighQualityBicubic
104        g.FillRectangle(Brushes.GhostWhite, 0, 0, width, height)
105        g.DrawRectangle(Pens.LightGray, 0, 0, width-1, height-1)
106        g.DrawImage(origImage, drawXOffset, drawYOffset, drawWidth, drawHeight)
107        imageBytes = BitmapToBytes(newImage)
108        # cleanup
109        g.Dispose()
110        newImage.Dispose()
111        origImage.Dispose()
112        return imageBytes
113
114    def thumbnail(self):
115        if self.__thumbnail is None: self.__thumbnail = self.__drawPictureThumbnail()
116        return self.__thumbnail
117
118def GetPicture(filename):
119    return GetCachedItem(PICTURE, filename)
120
121# FOLDER respesents info about one folder
122
123class FOLDER:
124    def __init__(self, path):
125        self.path = path
126        self.name = Path.GetFileName(self.path)
127        self.__thumbnail = None
128        self.__parentThumbnail = None
129
130    def __getFolderItems(self, picturesOnly, count):
131        if picturesOnly:
132            list = []
133        else:
134            def IsSpecialFolder(dir):
135                d = Path.GetFileName(dir).lower()
136                return d.startswith('_vti_') or  d.startswith('app_') or d.startswith('bin') or d.startswith('aspnet_')
137            list = [GetFolder(d) for d in Directory.GetDirectories(self.path)[:count] if not IsSpecialFolder(d)]
138            count -= len(list)
139        if count > 0:
140            list += [GetPicture(p) for p in Directory.GetFiles(self.path, '*.jpg')[:count]]
141        return list
142
143
144    def GetFirstFolderItems(self, count): return self.__getFolderItems(False, count)
145
146    def GetFolderItems(self): return self.__getFolderItems(False, 10000)
147
148    def GetFolderPictures(self): return self.__getFolderItems(True, 10000)
149
150    def __drawFolderThumbnail(self, parent):
151        size = ThumbnailSize
152        # create new image
153        newImage = Bitmap(size, size)
154        g = Graphics.FromImage(newImage)
155        g.InterpolationMode = InterpolationMode.HighQualityBicubic
156        # draw background
157        if parent: bc = ParentFolderColor
158        else:      bc = ChildFolderColor
159        b = LinearGradientBrush(Point(0, 0), Point(size, size), bc, Color.GhostWhite)
160        g.FillRectangle(b, 0, 0, size, size)
161        b.Dispose()
162        g.DrawRectangle(Pens.LightGray, 0, 0, size-1, size-1)
163        # draw up to 4 subitems
164        folderItems = self.GetFirstFolderItems(4)
165        delta = 10
166        side = (size-3*delta)/2-1
167        rects = (
168            Rectangle(delta + 3                , delta + 12                , side, side),
169            Rectangle(size / 2 + delta / 2 - 3 , delta + 12                , side, side),
170            Rectangle(delta + 3                , size / 2 + delta / 2 + 6  , side, side),
171            Rectangle(size / 2 + delta / 2 - 3 , size / 2 + delta / 2 + 6  , side, side))
172        for rect, item in zip(rects, folderItems):
173            subImage = Bitmap.FromStream(MemoryStream(item.thumbnail()), False)
174            g.DrawImage(subImage, rect)
175            subImage.Dispose()
176        for rect in rects:
177            g.DrawRectangle(Pens.LightGray, rect)
178        # draw folder name
179        if parent: name = '[..]'
180        else:      name = Path.GetFileName(self.path)
181        f = Font('Arial', 10)
182        g.DrawString(name, f, Brushes.Black, RectangleF(2, 2, size-2, size-2))
183        f.Dispose()
184        # get the bytes of the image
185        imageBytes = BitmapToBytes(newImage)
186        # cleanup
187        g.Dispose()
188        newImage.Dispose()
189        return imageBytes
190
191    def thumbnail(self):
192        if self.__thumbnail is None: self.__thumbnail = self.__drawFolderThumbnail(False)
193        return self.__thumbnail
194
195    def parentThumbnail(self):
196        if self.__parentThumbnail is None: self.__parentThumbnail = self.__drawFolderThumbnail(True)
197        return self.__parentThumbnail
198
199def GetFolder(path):
200    return GetCachedItem(FOLDER, path)
201
202# Virtual path helper
203
204class VPATH:
205    def __init__(self, str):
206        s = str.lower()
207        if s != '/' and s.endswith('/'): s = s.rstrip('/')
208        if not s.startswith('/') or s.find('/.') >= 0 or s.find('\\') >= 0:
209            raise Exception('invalid virtual path %s' % (str))
210        self.str = s
211
212    def encode(self):
213        return HttpUtility.UrlEncodeUnicode(self.str).Replace('\'', '%27').Replace('%2f', '/').Replace('+', '%20')
214
215    def physicalPath(self): return HostingEnvironment.MapPath(self.str)
216
217    def parent(self):
218        s = self.str
219        if s == '/': return None
220        s = s[0:s.rfind('/')]
221        if s == '': s = '/'
222        return VPATH(s)
223
224    def child(self, name):
225        if self.str == '/': return VPATH('/'+name)
226        else:               return VPATH(self.str+'/'+name)
227
228    def name(self):
229        s = self.str
230        if s == '/': return None
231        return s[s.rfind('/')+1:]
232
233    def isRoot(self): return self.str == VPATH.root().str
234
235
236    def underRoot(self):
237        r = VPATH.root().str
238        s = self.str
239        return r == '/' or r == s or s.startswith(r + '/')
240
241    __rootVPath = None
242
243    @staticmethod
244    def root():
245        if VPATH.__rootVPath is None: VPATH.__rootVPath = VPATH(Request.FilePath).parent()
246        return VPATH.__rootVPath
247
248# Request modes
249
250PreviewImageMode = 1
251ThumbnailImageMode = 2
252ParentThumbnailImageMode = 3
253
254# IMAGETAG represents data needed to produce an HTML image
255
256class IMAGETAG:
257    def __init__(self, mode, vpath):
258        p = vpath.encode()
259        self.Src = '?mode=%d&path=%s' % (mode, p)
260        if mode in (ThumbnailImageMode, ParentThumbnailImageMode):
261            if vpath.isRoot(): self.Link = '?'
262            else:              self.Link = '?path='+p
263            self.Width, self.Height = ThumbnailSize, ThumbnailSize
264            self.Alt = 'thumbnail for '+p
265        elif mode == PreviewImageMode:
266            self.Link = p
267            self.Width, self.Height = GetPicture(vpath.physicalPath()).CalcResizedDims(PreviewSize)
268            self.Alt = p
269
270# Request Processing
271
272# 'declare' events we could be handling
273def Page_Load(sender, e): pass
274def Page_Unload(sender, e): pass
275
276# parse the mode from the query string
277if Request.QueryString.mode is not None:
278    mode = int(Request.QueryString.mode)
279else:
280    mode = 0
281
282# parse the path from the query string
283if Request.QueryString.path is not None:
284    vpath = VPATH(Request.QueryString.path)
285    if not vpath.underRoot():
286        raise HttpException('invalid path - not in the handler scope')
287else:
288    vpath = VPATH.root()
289
290ppath = vpath.physicalPath()
291isFolder = Directory.Exists(ppath)
292if not isFolder and not File.Exists(ppath):
293    raise HttpException('invalid path - not found')
294
295# perform the action depending on the mode
296if mode > 0:
297    # response is an image
298    if mode == PreviewImageMode:
299        imageResponse = GetPicture(ppath).DrawResizedImage(PreviewSize)
300    elif mode == ThumbnailImageMode:
301        if isFolder: imageResponse = GetFolder(ppath).thumbnail()
302        else:        imageResponse = GetPicture(ppath).thumbnail()
303    elif mode == ParentThumbnailImageMode:
304        imageResponse = GetFolder(ppath).parentThumbnail()
305    
306    # output the image in Page_Unload event        
307    def Page_Unload(sender, e):
308        response = HttpContext.Current.Response
309        response.Clear()
310        response.ContentType = 'image/jpeg'
311        response.OutputStream.Write(imageResponse, 0, imageResponse.Length)
312        
313else:
314    pvpath = vpath.parent()
315
316    # response is HTML
317    if isFolder:
318        # folder view
319        def Page_Load(sender, e):
320            global ParentLink
321
322            Header.Title = vpath.str
323            AlbumMultiView.ActiveViewIndex = 0
324
325            if pvpath is not None and pvpath.underRoot():
326                ParentLink = IMAGETAG(ParentThumbnailImageMode, pvpath)
327                FolderViewParentLinkSpan.Visible = True
328
329            ThumbnailList.DataSource = [IMAGETAG(ThumbnailImageMode, vpath.child(i.name))
330                for i in GetFolder(ppath).GetFolderItems()]
331            ThumbnailList.DataBind()
332    else:
333        def Page_Load(sender, e):
334            global ParentLink, PreviousLink, PictureLink, NextLink
335            # single picture details view
336            AlbumMultiView.ActiveViewIndex = 1
337
338            ParentLink = IMAGETAG(ParentThumbnailImageMode, pvpath)
339
340            prevvpath = None
341            nextvpath = None
342            found = False
343
344            for pict in GetFolder(pvpath.physicalPath()).GetFolderPictures():
345                p = pvpath.child(pict.name)
346                if p.str == vpath.str:
347                    found = True
348                elif found:
349                    nextvpath = p
350                    break
351                else:
352                    prevvpath = p
353
354            if not found: prevvpath = None
355
356            if prevvpath is not None:
357                PreviousLink = IMAGETAG(ThumbnailImageMode, prevvpath)
358                PreviousLinkSpan.Visible = True
359            else:
360                NoPreviousLinkSpan.Visible = True
361
362            if found:
363                PictureLink = IMAGETAG(PreviewImageMode, vpath)
364                PictureLinkSpan.Visible = True
365
366            if nextvpath is not None:
367                NextLink = IMAGETAG(ThumbnailImageMode, nextvpath)
368                NextLinkSpan.Visible = True
369            else:
370                NoNextLinkSpan.Visible = True