OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Flattens a HTML file by inlining its external resources. | 6 """Flattens a HTML file by inlining its external resources. |
7 | 7 |
8 This is a small script that takes a HTML file, looks for src attributes | 8 This is a small script that takes a HTML file, looks for src attributes |
9 and inlines the specified file, producing one HTML file with no external | 9 and inlines the specified file, producing one HTML file with no external |
10 dependencies. It recursively inlines the included files. | 10 dependencies. It recursively inlines the included files. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 filename = filename.replace(DIST_SUBSTR , distribution) | 74 filename = filename.replace(DIST_SUBSTR , distribution) |
75 filepath = os.path.join(base_path, filename) | 75 filepath = os.path.join(base_path, filename) |
76 inlined_files.add(filepath) | 76 inlined_files.add(filepath) |
77 | 77 |
78 if names_only: | 78 if names_only: |
79 return "" | 79 return "" |
80 | 80 |
81 mimetype = mimetypes.guess_type(filename)[0] or 'text/plain' | 81 mimetype = mimetypes.guess_type(filename)[0] or 'text/plain' |
82 inline_data = base64.standard_b64encode(util.ReadFile(filepath, util.BINARY)) | 82 inline_data = base64.standard_b64encode(util.ReadFile(filepath, util.BINARY)) |
83 | 83 |
84 prefix = src_match.string[src_match.start():src_match.start('filename')-1] | 84 prefix = src_match.string[src_match.start():src_match.start('filename')] |
85 return "%s\"data:%s;base64,%s\"" % (prefix, mimetype, inline_data) | 85 suffix = src_match.string[src_match.end('filename'):src_match.end()] |
| 86 if prefix and prefix[-1] in '\'"': |
| 87 prefix = prefix[:-1] |
| 88 if suffix and suffix[0] in '\'"': |
| 89 suffix = suffix[1:] |
| 90 return '%s"data:%s;base64,%s"%s' % (prefix, mimetype, inline_data, suffix) |
86 | 91 |
87 | 92 |
88 class InlinedData: | 93 class InlinedData: |
89 """Helper class holding the results from DoInline(). | 94 """Helper class holding the results from DoInline(). |
90 | 95 |
91 Holds the inlined data and the set of filenames of all the inlined | 96 Holds the inlined data and the set of filenames of all the inlined |
92 files. | 97 files. |
93 """ | 98 """ |
94 def __init__(self, inlined_data, inlined_files): | 99 def __init__(self, inlined_data, inlined_files): |
95 self.inlined_data = inlined_data | 100 self.inlined_data = inlined_data |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 inlined_files.add(filepath) | 235 inlined_files.add(filepath) |
231 # When resolving CSS files we need to pass in the path so that relative URLs | 236 # When resolving CSS files we need to pass in the path so that relative URLs |
232 # can be resolved. | 237 # can be resolved. |
233 return '<style>%s</style>' % InlineCSSText( | 238 return '<style>%s</style>' % InlineCSSText( |
234 util.ReadFile(filepath, util.BINARY), filepath) | 239 util.ReadFile(filepath, util.BINARY), filepath) |
235 | 240 |
236 def InlineCSSImages(text, filepath=input_filepath): | 241 def InlineCSSImages(text, filepath=input_filepath): |
237 """Helper function that inlines external images in CSS backgrounds.""" | 242 """Helper function that inlines external images in CSS backgrounds.""" |
238 # Replace contents of url() for css attributes: content, background, | 243 # Replace contents of url() for css attributes: content, background, |
239 # or *-image. | 244 # or *-image. |
240 return re.sub('(?:content|background|[\w-]*-image):[^;]*' + | 245 return re.sub('(content|background|[\w-]*-image):[^;]*' + |
241 '(?:url\((?:\'|\")([^"\'\)\(]*)(?:\'|\")\)|' + | 246 '(url\((?P<quote1>"|\'|)[^"\'()]*(?P=quote1)\)|' + |
242 'image-set\(' + | 247 'image-set\(' + |
243 '([ ]*url\((?:\'|\")([^"\'\)\(]*)(?:\'|\")\)' + | 248 '([ ]*url\((?P<quote2>"|\'|)[^"\'()]*(?P=quote2)\)' + |
244 '[ ]*[0-9.]*x[ ]*(,[ ]*)?)*\))', | 249 '[ ]*[0-9.]*x[ ]*(,[ ]*)?)+\))', |
245 lambda m: InlineCSSUrls(m, filepath), | 250 lambda m: InlineCSSUrls(m, filepath), |
246 text) | 251 text) |
247 | 252 |
248 def InlineCSSUrls(src_match, filepath=input_filepath): | 253 def InlineCSSUrls(src_match, filepath=input_filepath): |
249 """Helper function that inlines each url on a CSS image rule match.""" | 254 """Helper function that inlines each url on a CSS image rule match.""" |
250 # Replace contents of url() references in matches. | 255 # Replace contents of url() references in matches. |
251 return re.sub('url\((?:\'|\")(?P<filename>[^"\'\)\(]*)(?:\'|\")', | 256 return re.sub('url\((?P<quote>"|\'|)(?P<filename>[^"\'()]*)(?P=quote)\)', |
252 lambda m: SrcReplace(m, filepath), | 257 lambda m: SrcReplace(m, filepath), |
253 src_match.group(0)) | 258 src_match.group(0)) |
254 | 259 |
255 | 260 |
256 | 261 |
257 flat_text = util.ReadFile(input_filename, util.BINARY) | 262 flat_text = util.ReadFile(input_filename, util.BINARY) |
258 | 263 |
259 if not allow_external_script: | 264 if not allow_external_script: |
260 # We need to inline css and js before we inline images so that image | 265 # We need to inline css and js before we inline images so that image |
261 # references gets inlined in the css and js | 266 # references gets inlined in the css and js |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 | 358 |
354 def main(): | 359 def main(): |
355 if len(sys.argv) <= 2: | 360 if len(sys.argv) <= 2: |
356 print "Flattens a HTML file by inlining its external resources.\n" | 361 print "Flattens a HTML file by inlining its external resources.\n" |
357 print "html_inline.py inputfile outputfile" | 362 print "html_inline.py inputfile outputfile" |
358 else: | 363 else: |
359 InlineToFile(sys.argv[1], sys.argv[2], None) | 364 InlineToFile(sys.argv[1], sys.argv[2], None) |
360 | 365 |
361 if __name__ == '__main__': | 366 if __name__ == '__main__': |
362 main() | 367 main() |
OLD | NEW |