├── Embedder ├── random.in ├── filenames.txt ├── tempstuff.sh ├── run_spidey.sh ├── run_godzilla.sh ├── embed_to_zero.txt ├── runner.sh ├── Embedder_0.py ├── Embedder_1.py ├── embed_1.cl └── embed_0.cl ├── steganography_ui ├── modules │ ├── joiner │ │ ├── instructions.sh │ │ ├── config.cfg │ │ ├── tempstuff │ │ ├── runner.sh │ │ └── joiner.py │ ├── embedder │ │ ├── README │ │ ├── gpu_embedder │ │ │ ├── tempstuff.sh │ │ │ ├── run_spidey.sh │ │ │ ├── run_godzilla.sh │ │ │ ├── runner.sh │ │ │ ├── Embedder_0.py │ │ │ ├── Embedder_1.py │ │ │ ├── embed_1.cl │ │ │ └── embed_0.cl │ │ └── cpu_embedder_slow │ │ │ └── newest_embedder.py │ ├── decoder │ │ ├── stuff │ │ │ ├── godzilla_package.tar │ │ │ └── godzilla_package │ │ │ │ └── godzilla_decoder.py │ │ ├── decoder_preprocessing.py │ │ └── decoder.py │ ├── calc_luminance │ │ ├── plotter.py │ │ ├── gpu_code │ │ │ ├── calc_luma.cl │ │ │ └── gpu_calc_luma.py │ │ └── cpu_code │ │ │ └── calc_luminance.py │ ├── README │ └── splitter │ │ ├── temp_runner.sh │ │ ├── splitter_with_dest.sh │ │ └── splitter.sh ├── web │ ├── slides │ │ ├── slide_1.html │ │ ├── slide_2.html │ │ └── slide_0.html │ ├── references.html │ ├── video_processing.html │ ├── index.html │ ├── overview.html │ ├── old_files │ │ ├── bold.html │ │ ├── base.html │ │ ├── file_upload.html │ │ └── sample_file.html │ ├── select_operations.html │ ├── transformed_rows.html │ ├── uploads.html │ ├── joiner.html │ ├── compare.html │ ├── video_upload.html │ ├── archives.html │ ├── detector.html │ ├── overview_slide.html │ ├── preprocessed_overview.html │ ├── compare_page.html │ ├── embedder.html │ ├── splitter.html │ ├── overview_slide_.html │ └── bootstrap_base.html ├── images │ ├── Picture1.jpg │ ├── Picture2.jpg │ ├── capture_1.jpg │ ├── capture_2.jpg │ ├── not_found.jpg │ ├── splitter_1.jpg │ ├── splitter_2.jpg │ ├── splitter_3.jpg │ ├── splitter_4.jpg │ ├── cam_rec_1_luma.png │ ├── cam_rec_2_luma.png │ ├── original_image.bmp │ ├── original_luma.png │ ├── carousel_background.jpg │ ├── decreased_luma_image.bmp │ └── increased_luma_image.bmp ├── tornado_handlers │ ├── decoder.pyc │ ├── plotter.pyc │ ├── __init__.pyc │ ├── new_img1.bmp │ ├── custom_utils.pyc │ ├── joiner_handler.pyc │ ├── archive_handler.pyc │ ├── compare_handler.pyc │ ├── detector_handler.pyc │ ├── embedder_handler.pyc │ ├── overview_handler.pyc │ ├── splitter_handler.pyc │ ├── transformations.pyc │ ├── uploads_handler.pyc │ ├── compare_files_handler.pyc │ ├── transformation_handler.pyc │ ├── video_processing_handler.pyc │ ├── joiner_handler.py │ ├── embedder_handler.py │ ├── splitter_handler.py │ ├── video_processing_handler.py │ ├── overview_handler.py │ ├── __init__.py │ ├── uploads_handler.py │ ├── compare_handler.py │ ├── decoder_preprocessing.py │ ├── archive_handler.py │ ├── plotter.py │ ├── custom_utils.py │ ├── detector_handler.py │ ├── transformations.py │ ├── transformation_handler.py │ ├── compare_files_handler.py │ └── decoder.py ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── reset.sh ├── backup.sh ├── js │ ├── video_processing_handlers.js │ ├── old_handlers.js │ ├── my_handlers.js │ ├── jquery.iframe-transport.js │ └── docs.min.js ├── css │ ├── dashboard.css │ ├── bootstrap-select.min.css │ ├── bootstrap-select.css │ ├── bootstrap-theme.min.css │ └── bootstrap-theme.css └── server.py └── README.md /Embedder/random.in: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /Embedder/filenames.txt: -------------------------------------------------------------------------------- 1 | test_image.bmp 2 | -------------------------------------------------------------------------------- /steganography_ui/modules/joiner/instructions.sh: -------------------------------------------------------------------------------- 1 | Insufficient frames 2 | -------------------------------------------------------------------------------- /steganography_ui/web/slides/slide_1.html: -------------------------------------------------------------------------------- 1 |

Welcome Again!

2 | -------------------------------------------------------------------------------- /steganography_ui/web/slides/slide_2.html: -------------------------------------------------------------------------------- 1 |

Welcome Once Again!

2 | -------------------------------------------------------------------------------- /steganography_ui/web/references.html: -------------------------------------------------------------------------------- 1 |
2 | References here... 3 |
4 | -------------------------------------------------------------------------------- /steganography_ui/web/slides/slide_0.html: -------------------------------------------------------------------------------- 1 |

Video Steganography for the prevention of piracy in the entertainment industry

2 | -------------------------------------------------------------------------------- /steganography_ui/web/video_processing.html: -------------------------------------------------------------------------------- 1 |
2 |

Video Processing

3 | {% include "video_upload.html" %} 4 |
5 | -------------------------------------------------------------------------------- /Embedder/tempstuff.sh: -------------------------------------------------------------------------------- 1 | xmen="/media/My Passport/Anthony/Steganography/Frames/xmen/" 2 | quantifier="Original/*.bmp" 3 | ls "$xmen"$quantifier > /tmp/abc 4 | -------------------------------------------------------------------------------- /steganography_ui/images/Picture1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/Picture1.jpg -------------------------------------------------------------------------------- /steganography_ui/images/Picture2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/Picture2.jpg -------------------------------------------------------------------------------- /steganography_ui/images/capture_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/capture_1.jpg -------------------------------------------------------------------------------- /steganography_ui/images/capture_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/capture_2.jpg -------------------------------------------------------------------------------- /steganography_ui/images/not_found.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/not_found.jpg -------------------------------------------------------------------------------- /steganography_ui/images/splitter_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/splitter_1.jpg -------------------------------------------------------------------------------- /steganography_ui/images/splitter_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/splitter_2.jpg -------------------------------------------------------------------------------- /steganography_ui/images/splitter_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/splitter_3.jpg -------------------------------------------------------------------------------- /steganography_ui/images/splitter_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/splitter_4.jpg -------------------------------------------------------------------------------- /steganography_ui/images/cam_rec_1_luma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/cam_rec_1_luma.png -------------------------------------------------------------------------------- /steganography_ui/images/cam_rec_2_luma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/cam_rec_2_luma.png -------------------------------------------------------------------------------- /steganography_ui/images/original_image.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/original_image.bmp -------------------------------------------------------------------------------- /steganography_ui/images/original_luma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/original_luma.png -------------------------------------------------------------------------------- /steganography_ui/modules/joiner/config.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "bucket_size": 8, 3 | "normal_size": 100, 4 | "bitstring_size": 8, 5 | "min_robustness_count": 6 6 | } 7 | -------------------------------------------------------------------------------- /steganography_ui/web/index.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap_base.html" %} 2 | 3 | {% block dashboard_content %} 4 | {% include "preprocessed_overview.html" %} 5 | {% end %} 6 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/decoder.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/decoder.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/plotter.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/plotter.pyc -------------------------------------------------------------------------------- /steganography_ui/images/carousel_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/carousel_background.jpg -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/__init__.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/new_img1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/new_img1.bmp -------------------------------------------------------------------------------- /steganography_ui/images/decreased_luma_image.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/decreased_luma_image.bmp -------------------------------------------------------------------------------- /steganography_ui/images/increased_luma_image.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/images/increased_luma_image.bmp -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/custom_utils.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/custom_utils.pyc -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/README: -------------------------------------------------------------------------------- 1 | Embedder preprocesses the frames into one's and zero's. 2 | Not to be run on cpu. 3 | Use computer with GPU 4 | Time and computation intensive task 5 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/tempstuff.sh: -------------------------------------------------------------------------------- 1 | xmen="/media/My Passport/Anthony/Steganography/Frames/xmen/" 2 | quantifier="Original/*.bmp" 3 | ls "$xmen"$quantifier > /tmp/abc 4 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/joiner_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/joiner_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/web/overview.html: -------------------------------------------------------------------------------- 1 |

Video Steganography for the prevention of piracy in the entertainment industry

2 | 3 |

Write the description of the project here...

4 | -------------------------------------------------------------------------------- /steganography_ui/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /steganography_ui/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/archive_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/archive_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/compare_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/compare_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/detector_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/detector_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/embedder_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/embedder_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/overview_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/overview_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/splitter_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/splitter_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/transformations.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/transformations.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/uploads_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/uploads_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /steganography_ui/modules/decoder/stuff/godzilla_package.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/modules/decoder/stuff/godzilla_package.tar -------------------------------------------------------------------------------- /steganography_ui/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | bash backup.sh 3 | tree -L 1 images/ uploads/ video/ 4 | rm -f images/*.png 5 | rm -f uploads/* 6 | rm -f video/* 7 | tree -L 1 images/ uploads/ video/ 8 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/compare_files_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/compare_files_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/transformation_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/transformation_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/video_processing_handler.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityangud/Video-Steganography-for-Piracy-Prevention/HEAD/steganography_ui/tornado_handlers/video_processing_handler.pyc -------------------------------------------------------------------------------- /steganography_ui/web/old_files/bold.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}A bolder title{% end %} 4 | 5 | {% block student %} 6 |
  • {{ escape(student.name) }}
  • 7 | {% end %} 8 | -------------------------------------------------------------------------------- /steganography_ui/backup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | current_date=`date +"%d-%m-%Y-%H-%M-%S"`; 3 | folder_name=$(basename `pwd`); 4 | cd ..; 5 | tar -cvzf "stego_$current_date.tgz" $folder_name; 6 | ls *.tgz; 7 | cd -; 8 | echo "done" 9 | -------------------------------------------------------------------------------- /steganography_ui/modules/joiner/tempstuff: -------------------------------------------------------------------------------- 1 | NORMAL_FOLDER=/media/anthony/Seagate1/SplitFrames/Godzilla/Frames 2 | OUTPUT_FOLDER=/media/anthony/Seagate/godzilla_stego_frames 3 | EMBED_ONE=/media/anthony/Seagate/EmbedFrames/Godzilla/embed_1 4 | EMBED_ZERO=/media/anthony/Seagate1/EmbedFrames/Godzilla/embed_0 5 | -------------------------------------------------------------------------------- /steganography_ui/web/select_operations.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /steganography_ui/web/old_files/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% block title %}Steganography{% end %} 4 | 5 | {% block extra_scripts %} 6 | {% end %} 7 | 8 | {% block body %} 9 | {% end %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /Embedder/run_spidey.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export PYOPENCL_CTX='0'; 4 | 5 | ls /media/Seagate__/SplitFrames/Spidey/Frames/*.bmp > spider_frames.txt 6 | 7 | python Embedder_1.py spider_frames.txt /media/Seagate___/EmbedFrames/Spidey/embed_1 8 | 9 | python Embedder_0.py spider_frames.txt /media/Seagate___/EmbedFrames/Spidey/embed_0 10 | 11 | -------------------------------------------------------------------------------- /steganography_ui/web/old_files/file_upload.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block body %} 4 |

    Select and upload

    5 |
    6 | File: 7 |
    8 | 9 |
    10 | {% end %} 11 | -------------------------------------------------------------------------------- /Embedder/run_godzilla.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export PYOPENCL_CTX='0'; 4 | 5 | ls /media/Seagate__/SplitFrames/Godzilla/Frames/*.bmp > godzilla_frames.txt 6 | 7 | python Embedder_0.py godzilla_frames.txt /media/Seagate__/EmbedFrames/Godzilla/embed_0 8 | 9 | python Embedder_1.py godzilla_frames.txt /media/Seagate___/EmbedFrames/Godzilla/embed_1 10 | 11 | -------------------------------------------------------------------------------- /steganography_ui/modules/calc_luminance/plotter.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot 2 | import sys 3 | 4 | def plotter(filename): 5 | fp = open(filename) 6 | values = eval(fp.read()) 7 | lines = pyplot.plot(range(0, len(values)), values) 8 | pyplot.savefig(filename + '.png') 9 | 10 | if __name__ == '__main__': 11 | filename = sys.argv[1] 12 | plotter(filename) 13 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/run_spidey.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export PYOPENCL_CTX='0'; 4 | 5 | ls /media/Seagate__/SplitFrames/Spidey/Frames/*.bmp > spider_frames.txt 6 | 7 | python Embedder_1.py spider_frames.txt /media/Seagate___/EmbedFrames/Spidey/embed_1 8 | 9 | python Embedder_0.py spider_frames.txt /media/Seagate___/EmbedFrames/Spidey/embed_0 10 | 11 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/run_godzilla.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export PYOPENCL_CTX='0'; 4 | 5 | ls /media/Seagate__/SplitFrames/Godzilla/Frames/*.bmp > godzilla_frames.txt 6 | 7 | python Embedder_0.py godzilla_frames.txt /media/Seagate__/EmbedFrames/Godzilla/embed_0 8 | 9 | python Embedder_1.py godzilla_frames.txt /media/Seagate___/EmbedFrames/Godzilla/embed_1 10 | 11 | -------------------------------------------------------------------------------- /steganography_ui/web/transformed_rows.html: -------------------------------------------------------------------------------- 1 | 2 | {% for document in documents %} 3 | 4 | graph of {{ document['name'] }} 5 | 6 | {% end %} 7 | 8 | {% include "select_operations.html" %} 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/joiner_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | 5 | class JoinerHandler(tornado.web.RequestHandler): 6 | loader = template.Loader('./web') 7 | def post(self): 8 | print "got request for joiner" 9 | html = self.loader.load('joiner.html').generate() 10 | data = json.dumps({'html': html}) 11 | self.write(data) 12 | 13 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/embedder_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | 5 | class EmbedderHandler(tornado.web.RequestHandler): 6 | loader = template.Loader('./web') 7 | def post(self): 8 | print "got request for embedder" 9 | html = self.loader.load('embedder.html').generate() 10 | data = json.dumps({'html': html}) 11 | self.write(data) 12 | 13 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/splitter_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | 5 | class SplitterHandler(tornado.web.RequestHandler): 6 | loader = template.Loader('./web') 7 | def post(self): 8 | print "got request for splitter" 9 | html = self.loader.load('splitter.html').generate() 10 | data = json.dumps({'html': html}) 11 | self.write(data) 12 | 13 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/video_processing_handler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tornado.ioloop 3 | import tornado.web 4 | from tornado import template 5 | import json 6 | 7 | 8 | class VideoProcessingHandler(tornado.web.RequestHandler): 9 | loader = template.Loader('./web') 10 | def post(self): 11 | html = self.loader.load('video_processing.html').generate() 12 | self.write(json.dumps({'html': html})) 13 | 14 | 15 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/overview_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | 5 | class OverviewHandler(tornado.web.RequestHandler): 6 | loader = template.Loader('./web') 7 | def post(self): 8 | print "got request for overview" 9 | html = self.loader.load('preprocessed_overview.html').generate() 10 | data = json.dumps({'html': html}) 11 | self.write(data) 12 | 13 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'overview_handler', 3 | 'archive_handler', 4 | 'compare_files_handler', 5 | 'compare_handler', 6 | 'custom_utils', 7 | 'overview_handler', 8 | 'plotter', 9 | 'transformation_handler', 10 | 'transformations', 11 | 'uploads_handler', 12 | 'video_processing_handler', 13 | 'joiner_handler', 14 | 'splitter_handler', 15 | 'embedder_handler', 16 | 'detector_handler', 17 | ] 18 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/uploads_handler.py: -------------------------------------------------------------------------------- 1 | from tornado import template 2 | import tornado.web 3 | import json 4 | 5 | 6 | class UploadsHandler(tornado.web.RequestHandler): 7 | 8 | loader = template.Loader('./web') 9 | 10 | def post(self): 11 | self.loader = template.Loader('./web') 12 | num_uploads = self.get_argument('num_uploads') 13 | html_data = self.loader.load('uploads.html').generate(num_uploads=num_uploads) 14 | data = json.dumps({'html': html_data}) 15 | self.write(data) 16 | 17 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/compare_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | 5 | from custom_utils import * 6 | 7 | class CompareHandler(tornado.web.RequestHandler): 8 | loader = template.Loader('./web') 9 | def post(self): 10 | print "got request for overview" 11 | documents = get_documents() 12 | print documents 13 | html = self.loader.load('compare_page.html').generate(documents=documents) 14 | 15 | data = json.dumps({'html': html}) 16 | self.write(data) 17 | 18 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/decoder_preprocessing.py: -------------------------------------------------------------------------------- 1 | 2 | def decoder_preprocessing_spidey(a, b): 3 | a = a[75:-75] 4 | 5 | avg_b_74 = float(sum(b[:74]))/len(b[:74]) 6 | for i in xrange(len(b)): 7 | b[i] = b[i] - avg_b_74 8 | 9 | avg_a = float(sum(a))/len(a) 10 | avg_b = float(sum(b))/len(b) 11 | 12 | b = b[74:] 13 | 14 | new_avg_b = float(sum(b))/len(b) 15 | length = len(b) 16 | a = a[:length] 17 | 18 | for i in xrange(length): 19 | a[i] = a[i] - avg_a 20 | b[i] = b[i] - new_avg_b 21 | 22 | return (a, b) 23 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/archive_handler.py: -------------------------------------------------------------------------------- 1 | from tornado import template 2 | import tornado.web 3 | import json 4 | import time 5 | import os 6 | 7 | from custom_utils import * 8 | 9 | class ArchiveHandler(tornado.web.RequestHandler): 10 | 11 | loader = template.Loader('./web') 12 | 13 | def post(self): 14 | self.loader = template.Loader('./web') 15 | documents = get_documents() 16 | html_data = self.loader.load('archives.html').generate(documents=documents) 17 | data = json.dumps({'html': html_data}) 18 | self.write(data) 19 | 20 | -------------------------------------------------------------------------------- /steganography_ui/modules/joiner/runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mkdir joiner_result 3 | normal_folder="/media/anthony/Seagate/SplitFrames/Spidey/Frames/" 4 | zero_folder="/media/anthony/Seagate3/EmbedFrames/Spidey/embed_0/"; 5 | one_folder="/media/anthony/Seagate3/EmbedFrames/Spidey/embed_1/" 6 | bitstring="11110000"; 7 | output_folder="joiner_result"; 8 | 9 | python joiner.py $normal_folder $one_folder $zero_folder $bitstring $output_folder > instructions.sh 10 | echo "done run bash instructions.sh" 11 | exit 12 | bash instructions.sh 13 | cd $output_folder 14 | ffmpeg -qscale 1 -r 25 -b 32028 -i img_embed_%08d.bmp output.mp4 15 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/plotter.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot 2 | import sys 3 | 4 | def plotter(filename, save_name=None): 5 | print "plotting %s" % filename 6 | fp = open(filename) 7 | values = eval(fp.read()) 8 | lines = pyplot.plot(range(0, len(values)), values) 9 | pyplot.title(filename) 10 | if save_name: 11 | pyplot.savefig(save_name) 12 | else: 13 | pyplot.show() 14 | pyplot.gcf().clear() 15 | 16 | if __name__ == '__main__': 17 | filename = sys.argv[1] 18 | save_name = None 19 | if len(sys.argv) == 3: 20 | save_name = sys.argv[2] 21 | 22 | plotter(filename, save_name) 23 | -------------------------------------------------------------------------------- /Embedder/embed_to_zero.txt: -------------------------------------------------------------------------------- 1 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000201.bmp 2 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000202.bmp 3 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000203.bmp 4 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000204.bmp 5 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000205.bmp 6 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000206.bmp 7 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000207.bmp 8 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000208.bmp 9 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000209.bmp 10 | /media/Seagate__/SplitFrames/Godzilla/Frames/image_00000210.bmp 11 | -------------------------------------------------------------------------------- /steganography_ui/modules/README: -------------------------------------------------------------------------------- 1 | 1. MODULES 2 | tree modules/ 3 | 4 | 2. Splitter 5 | move to splitter/ 6 | 7 | 3. EMBEDDER 8 | move to embedder/ 9 | SHOW FILES IN /media/anthony/Seagate3/EmbedFrames/Spidey/ 10 | Normal frames in /media/anthony/Seagate/SplitFrames/ 11 | 12 | 4. Calc luminance 13 | move to calc_luminance/ 14 | play calc_luminance video 15 | 16 | 5. Joiner 17 | move to joiner/ 18 | NORMAL /media/anthony/Seagate/SplitFrames/Spidey/Frames 19 | ONE /media/anthony/Seagate3/EmbedFrames/Spidey/embed_1 20 | ZERO /media/anthony/Seagate3/EmbedFrames/Spidey/embed_0 21 | 22 | bash runner.sh 23 | 24 | 6. Decoder 25 | move to decoder 26 | Show on webpage 27 | 28 | 29 | -------------------------------------------------------------------------------- /steganography_ui/web/old_files/sample_file.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block extra_scripts %} 4 | 5 | 6 | 7 | 8 | {% end %} 9 | 10 | {% block body %} 11 | 12 |
    13 | 14 |
    15 |
    16 |
    17 |
    18 |
    19 | 20 | 21 | {% end %} 22 | 23 | 24 | -------------------------------------------------------------------------------- /steganography_ui/web/uploads.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 |
    6 | 7 |
    8 |
    9 |
    10 |
    11 | 0% Complete 12 |
    13 |
    14 |
    15 |
    16 | -------------------------------------------------------------------------------- /steganography_ui/modules/decoder/decoder_preprocessing.py: -------------------------------------------------------------------------------- 1 | 2 | a = eval(open('original_spidey.repr').read().strip()) 3 | b = eval(open('recorded_spidey.repr').read().strip()) 4 | 5 | a = a[75:-75] 6 | 7 | avg_b_74 = float(sum(b[:74]))/len(b[:74]) 8 | for i in xrange(len(b)): 9 | b[i] = b[i] - avg_b_74 10 | 11 | avg_a = float(sum(a))/len(a) 12 | avg_b = float(sum(b))/len(b) 13 | 14 | b = b[74:] 15 | 16 | new_avg_b = float(sum(b))/len(b) 17 | length = len(b) 18 | a = a[:length] 19 | 20 | for i in xrange(length): 21 | a[i] = a[i] - avg_a 22 | b[i] = b[i] - new_avg_b 23 | 24 | fp1 = open('new_original_spidey_1.repr', 'wb') 25 | fp1.write(repr(a)) 26 | fp2 = open('new_recorded_spidey_1.repr', 'wb') 27 | fp2.write(repr(b)) 28 | fp1.close() 29 | fp2.close() 30 | -------------------------------------------------------------------------------- /steganography_ui/modules/calc_luminance/gpu_code/calc_luma.cl: -------------------------------------------------------------------------------- 1 | __kernel void calc_luma(__global const uchar *a, __global long *c) 2 | { 3 | int imgid = get_global_id(0); 4 | 5 | int nrows = %d; 6 | int ncols = %d; 7 | int npix = %d; 8 | 9 | int i,j, luma_index, rowid; 10 | int img_index = imgid * nrows * ncols * npix; 11 | 12 | int r,g, b; 13 | 14 | long total_luma = 0; 15 | for(i=0; i < nrows; i++){ 16 | rowid = i * ncols * npix; 17 | for(j=0; j < ncols; j++){ 18 | luma_index = img_index + rowid + j * npix; 19 | r = a[luma_index]; 20 | g = a[luma_index + 1]; 21 | b = a[luma_index + 2]; 22 | total_luma += (long)(0.2126 * r + 0.7152 * g + 0.0722 * b); 23 | } 24 | } 25 | c[imgid] = (total_luma); 26 | } 27 | -------------------------------------------------------------------------------- /steganography_ui/web/joiner.html: -------------------------------------------------------------------------------- 1 |
    2 |

    JOINER

    3 |
    4 | 5 |

    Joiner is responsible for joining stego frames in a fashion determined by the input string (Transaction ID)

    6 |

    A two minute video in frames is around 20 GB. Joiner needs 4 folders 7 |

      8 |
    1. Normal folder of frames (unmodified)
    2. 9 |
    3. One folder containing frames with increased luminance
    4. 10 |
    5. Zero folder containing frames with decreased luminance
    6. 11 |
    7. Output folder, where frames from the previous 3 will be joined in some fashion to embed the bitstring
    8. 12 |
    13 | 14 |

    15 |

    Joiner needs enough space for all of this, and an external HD mounts differently each time

    16 |

    Run from shell to be sure , web based query might be faulty

    17 |
    18 | -------------------------------------------------------------------------------- /steganography_ui/web/compare.html: -------------------------------------------------------------------------------- 1 | {% block extra_scripts %} 2 | 3 | 4 | {% end %} 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | {% for document in documents %} 12 | 13 | {% end %} 14 | 17 | 18 | 19 | 20 | {% include "transformed_rows.html" %} 21 | 22 |
    {{ document['name'] }} 15 | Transformations 16 |
    23 |
    24 |
    25 | -------------------------------------------------------------------------------- /steganography_ui/web/video_upload.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | 7 | 13 | 20 | 21 |
    5 | 6 | 8 | 12 | 14 |
    15 |
    16 | 0% Complete 17 |
    18 |
    19 |
    22 |
    23 | 24 | -------------------------------------------------------------------------------- /steganography_ui/web/archives.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% for document in documents %} 13 | 14 | 15 | 16 | 17 | 18 | {% end %} 19 |
    Name Size (bytes) Last Modified
    {{ document['name'] }} {{ document['size'] }} {{ document['last-modified'] }}
    20 |
    21 |
    22 |
    23 | 24 | 25 |
    26 |
    27 | -------------------------------------------------------------------------------- /steganography_ui/modules/splitter/temp_runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mkdir "/media/anthony/My Passport/Anthony/Steganography/Frames/dragon"; 4 | ./splitter_with_dest.sh "/media/anthony/My Passport/Anthony/Steganography/Trailers/dragon.mp4" "/media/anthony/My Passport/Anthony/Steganography/Frames/dragon/Original" 5 | 6 | 7 | mkdir "/media/anthony/My Passport/Anthony/Steganography/Frames/captain_america"; 8 | ./splitter_with_dest.sh "/media/anthony/My Passport/Anthony/Steganography/Trailers/captain_america.mov" "/media/anthony/My Passport/Anthony/Steganography/Frames/captain_america/Original" 9 | 10 | 11 | mkdir "/media/anthony/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2"; 12 | ./splitter_with_dest.sh "/media/anthony/My Passport/Anthony/Steganography/Trailers/spiderman_trailer_2.mp4" "/media/anthony/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/Original" 13 | 14 | 15 | mkdir "/media/anthony/My Passport/Anthony/Steganography/Frames/xmen"; 16 | ./splitter_with_dest.sh "/media/anthony/My Passport/Anthony/Steganography/Trailers/xmen.mov" "/media/anthony/My Passport/Anthony/Steganography/Frames/xmen/Original" 17 | 18 | 19 | echo "done"; 20 | -------------------------------------------------------------------------------- /steganography_ui/js/video_processing_handlers.js: -------------------------------------------------------------------------------- 1 | function videoUploadHandler(){ 2 | $('#videoUpload').fileupload({ 3 | dataType: 'json', 4 | add: function(e, data){ 5 | console.log(data.files[0].name); 6 | console.log("added"); 7 | data.context = $('#video_upload_button').click(function() { 8 | data.submit(); 9 | }); 10 | }, 11 | done: function(e, data){ 12 | data.context.removeClass('glyphicon-upload'); 13 | data.context.addClass('glyphicon-ok'); 14 | console.log(data); 15 | $('#video_upload_div').replaceWith(data.result.html); 16 | }, 17 | progressall: function(e, data){ 18 | var progress = parseInt(data.loaded / data.total * 100, 10); 19 | $('.progress-bar').css('width', progress + '%'); 20 | }, 21 | }); 22 | }; 23 | 24 | function onNavVideoProcessing(){ 25 | console.log("navigated to video processing"); 26 | $.post('/video_processing/', {}, function(data, textstatus, xhrstuff){ 27 | data = JSON.parse(data); 28 | $('#replaceable_content').children().remove(); 29 | $('#replaceable_content').append(data.html); 30 | videoUploadHandler(); 31 | }); 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /steganography_ui/modules/splitter/splitter_with_dest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | filename=$(basename "$1"); 3 | extension="${filename##*.}"; 4 | filename="${filename%.*}"; 5 | pretty_separator="-----------------------------------------------------------------------"; 6 | image_dir=$2; 7 | 8 | if [[ -z "$1" ]]; then 9 | echo "Usage: ./anto_script.sh video_file destination_folder [framerate=25]" 10 | exit; 11 | fi 12 | if [[ -z "$3" ]]; then 13 | frame_rate=25; 14 | else 15 | frame_rate=$3; 16 | fi 17 | 18 | echo $pretty_separator; 19 | 20 | if [ -d "$image_dir" ]; then 21 | echo "Directory $image_dir already exists"; 22 | read -p "Delete directory and continue Y/n? " -n 1 -r 23 | echo # (optional) move to a new line 24 | if [[ $REPLY =~ ^[Yy]$ ]] 25 | then 26 | # do dangerous stuff 27 | rm -rf "$image_dir"; 28 | else 29 | echo "remove and run this again "; 30 | exit; 31 | fi 32 | fi 33 | echo "creating $image_dir"; 34 | mkdir "$image_dir"; 35 | 36 | echo "running ffmpeg on $filename storing images in $image_dir, modify script to change framerate, default $frame_rate"; 37 | echo $pretty_separator; 38 | 39 | ffmpeg -i "$1" -r $frame_rate -f image2 "$image_dir/image_%08d.bmp"; 40 | 41 | echo $pretty_separator; 42 | echo "done"; 43 | -------------------------------------------------------------------------------- /steganography_ui/web/detector.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    5 | 6 |
    7 | 8 |
    9 | 10 |
    11 |
    12 | 13 |

    Detector

    14 | 15 | {% if bitstring %} 16 |

    The result is : {{ bitstring }}

    17 | {% end %} 18 | 19 |
    20 |

    Given two files containing the luminance values , as well as the configuration file, it will return the detected code

    21 | 22 |
    23 | 24 |
    25 | 26 |
    27 | 28 |
    29 | 30 |
    31 | 32 |
    33 | 34 | 35 | 36 |
    37 | 38 |
    39 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/custom_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import types 4 | import transformations 5 | 6 | __UPLOADS__ = './uploads/' 7 | 8 | AVAILABLE_TRANSFORMATIONS = [ t for t in dir(transformations) 9 | if type(getattr(transformations, t)) == types.FunctionType 10 | and not t.startswith('_') ] 11 | 12 | 13 | 14 | file_not_supported = lambda x: {'name': x + "_NOT_SUPPORTED", 'link': os.path.join(__UPLOADS__, x), 'compatiable': False, 'image_link': '/images/not_found.jpg'} 15 | file_not_found = lambda x: {'name': x + "_NOT_FOUND", 'link': '#', 'compatiable': False, 'image_link': '/images/not_found.jpg'} 16 | file_supported = lambda x: {'name': x, 'link': os.path.join(__UPLOADS__, x), 'compatiable': True} 17 | 18 | 19 | 20 | 21 | def file_info(filename): 22 | (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(__UPLOADS__ + filename) 23 | return_data = {"name": filename, "size": size, "last-modified": time.ctime(mtime)} 24 | return return_data; 25 | 26 | 27 | def get_documents(): 28 | return map(file_info, os.listdir('./uploads')) 29 | 30 | 31 | def renderable_as_graph(filename): 32 | fp = open(os.path.join(__UPLOADS__, filename)) 33 | try: 34 | data = eval(fp.read()) 35 | one_element = data[0] 36 | fp.close() 37 | except Exception as exception: 38 | fp.close() 39 | return False 40 | 41 | return True 42 | -------------------------------------------------------------------------------- /steganography_ui/web/overview_slide.html: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /steganography_ui/web/preprocessed_overview.html: -------------------------------------------------------------------------------- 1 | 43 | -------------------------------------------------------------------------------- /steganography_ui/modules/calc_luminance/cpu_code/calc_luminance.py: -------------------------------------------------------------------------------- 1 | import Image 2 | import sys 3 | 4 | # luminance per pixel formula 5 | luma = lambda r,g,b: long((0.2126 * r) + (0.7152 * g) + (0.0722 * b)) 6 | 7 | def get_filenames(filenames_file): 8 | ''' 9 | returns the filenames from the file one by one 10 | ''' 11 | fp = open(filenames_file) 12 | data = fp.read() 13 | fp.close() 14 | 15 | lines = [i.strip() for i in data.split('\n')] 16 | return [i for i in lines if i != ''] 17 | 18 | def calc_luma(filename): 19 | ''' 20 | Reads filename as an image and calculates average luminance 21 | ''' 22 | im = Image.open(filename) 23 | rows, cols = im.size 24 | pixels = im.load() 25 | 26 | luma_sum = 0 27 | for i in xrange(rows): 28 | for j in xrange(cols): 29 | luma_sum += luma(*pixels[i, j]) 30 | 31 | # avg luminance is sum / number of pixels 32 | return luma_sum / (rows * cols) 33 | 34 | 35 | if __name__ == '__main__': 36 | if len(sys.argv) is not 2: 37 | print "usage python calc_luma.py " 38 | sys.exit(0) 39 | 40 | filenames_file = sys.argv[1] 41 | 42 | filenames = get_filenames(filenames_file) 43 | total = len(filenames) 44 | 45 | luma_list = [] 46 | sys.stderr.write('0'); 47 | sys.stderr.flush(); 48 | i = 1.0 49 | 50 | for filename in get_filenames(filenames_file): 51 | sys.stderr.write('\r%d%%' % ((i / total ) * 100)) 52 | sys.stderr.flush() 53 | luma_list.append(calc_luma(filename)) 54 | i = i + 1.0 55 | 56 | sys.stderr.write('\r') 57 | sys.stderr.flush() 58 | print repr(luma_list) 59 | -------------------------------------------------------------------------------- /steganography_ui/modules/splitter/splitter.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | filename=$(basename "$1"); 3 | extension="${filename##*.}"; 4 | filename="${filename%.*}"; 5 | pretty_separator="-----------------------------------------------------------------------"; 6 | 7 | 8 | if [[ -z "$1" ]]; then 9 | echo "Usage: ./anto_script.sh video_file [framerate=25]" 10 | exit; 11 | fi 12 | if [[ -z "$2" ]]; then 13 | frame_rate=25; 14 | else 15 | frame_rate=$2; 16 | fi 17 | 18 | echo $pretty_separator; 19 | image_dir="images_$filename"; 20 | if [ -d "$image_dir" ]; then 21 | echo "Directory $image_dir already exists"; 22 | read -p "Delete directory and continue Y/n? " -n 1 -r 23 | echo # (optional) move to a new line 24 | if [[ $REPLY =~ ^[Yy]$ ]] 25 | then 26 | # do dangerous stuff 27 | rm -rf $image_dir; 28 | else 29 | echo "remove and run this again "; 30 | exit; 31 | fi 32 | fi 33 | echo "creating $image_dir"; 34 | mkdir $image_dir; 35 | 36 | echo "running ffmpeg on $filename storing images in $image_dir, modify script to change framerate, default $frame_rate"; 37 | echo $pretty_separator; 38 | 39 | ffmpeg -i $1 -r $frame_rate -f image2 $image_dir/image_%08d.bmp; 40 | 41 | echo $pretty_separator; 42 | 43 | ls -d -1 $PWD/$image_dir/*.bmp > $image_dir/filenames.txt; 44 | echo "calling calc_luminance.py on the images, saved at $image_dir/luminance_values"; 45 | python calc_luminance.py $image_dir/filenames.txt > $image_dir/luminance_values.repr ; 46 | 47 | echo $pretty_separator; 48 | 49 | echo "Creating graph and saving in $image_dir/luminance_values.repr.bmp"; 50 | python plotter.py $image_dir/luminance_values.repr ; 51 | # eog $image_dir/luminance_values.repr.bmp; 52 | echo "done"; 53 | -------------------------------------------------------------------------------- /steganography_ui/web/compare_page.html: -------------------------------------------------------------------------------- 1 |
    2 | Select files to compare 3 | 4 | 5 |
    6 | 7 | 8 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /steganography_ui/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Base structure 3 | */ 4 | 5 | /* Move down content because we have a fixed navbar that is 50px tall */ 6 | body { 7 | padding-top: 50px; 8 | } 9 | 10 | 11 | /* 12 | * Global add-ons 13 | */ 14 | 15 | .sub-header { 16 | padding-bottom: 10px; 17 | border-bottom: 1px solid #eee; 18 | } 19 | 20 | 21 | /* 22 | * Sidebar 23 | */ 24 | 25 | /* Hide for mobile, show later */ 26 | .sidebar { 27 | display: none; 28 | } 29 | @media (min-width: 768px) { 30 | .sidebar { 31 | position: fixed; 32 | top: 51px; 33 | bottom: 0; 34 | left: 0; 35 | z-index: 1000; 36 | display: block; 37 | padding: 20px; 38 | overflow-x: hidden; 39 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 40 | background-color: #f5f5f5; 41 | border-right: 1px solid #eee; 42 | } 43 | } 44 | 45 | /* Sidebar navigation */ 46 | .nav-sidebar { 47 | margin-right: -21px; /* 20px padding + 1px border */ 48 | margin-bottom: 20px; 49 | margin-left: -20px; 50 | } 51 | .nav-sidebar > li > a { 52 | padding-right: 20px; 53 | padding-left: 20px; 54 | } 55 | .nav-sidebar > .active > a { 56 | color: #fff; 57 | background-color: #428bca; 58 | } 59 | 60 | 61 | /* 62 | * Main content 63 | */ 64 | 65 | .main { 66 | padding: 20px; 67 | } 68 | @media (min-width: 768px) { 69 | .main { 70 | padding-right: 40px; 71 | padding-left: 40px; 72 | } 73 | } 74 | .main .page-header { 75 | margin-top: 0; 76 | } 77 | 78 | 79 | /* 80 | * Placeholder dashboard ideas 81 | */ 82 | 83 | .placeholders { 84 | margin-bottom: 30px; 85 | text-align: center; 86 | } 87 | .placeholders h4 { 88 | margin-bottom: 0; 89 | } 90 | .placeholder { 91 | margin-bottom: 20px; 92 | } 93 | .placeholder img { 94 | display: inline-block; 95 | border-radius: 50%; 96 | } 97 | -------------------------------------------------------------------------------- /Embedder/runner.sh: -------------------------------------------------------------------------------- 1 | xmen="/media/My Passport/Anthony/Steganography/Frames/xmen/"; 2 | dragon="/media/My Passport/Anthony/Steganography/Frames/dragon/"; 3 | captain="/media/My Passport/Anthony/Steganography/Frames/captain_america/"; 4 | spider="/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/"; 5 | 6 | additional="Original/*.bmp" 7 | 8 | ls "$xmen"$additional > xmen_filenames.txt 9 | ls "$captain"$additional > dragon_filenames.txt 10 | ls "$captain"$additional > captain_america_filenames.txt 11 | ls "$spider"$additional > spiderman_trailer_2_filenames.txt 12 | 13 | 14 | echo "DRAGON"; 15 | export PYOPENCL_CTX='0'; 16 | python Embedder_1.py dragon_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/dragon/Embed_1/" 17 | export PYOPENCL_CTX='0'; 18 | python Embedder_0.py dragon_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/dragon/Embed_0/" 19 | 20 | 21 | echo "SPIDERMAN"; 22 | export PYOPENCL_CTX='0'; 23 | python Embedder_1.py spiderman_trailer_2_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/Embed_1/" 24 | export PYOPENCL_CTX='0'; 25 | python Embedder_0.py spiderman_trailer_2_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/Embed_0/" 26 | 27 | 28 | echo "captain_america"; 29 | export PYOPENCL_CTX='0'; 30 | python Embedder_1.py captain_america_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/captain_america/Embed_1/" 31 | export PYOPENCL_CTX='0'; 32 | python Embedder_0.py captain_america_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/captain_america/Embed_0/" 33 | 34 | echo "xmen"; 35 | export PYOPENCL_CTX='0'; 36 | python Embedder_1.py xmen_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/xmen/Embed_1/" 37 | export PYOPENCL_CTX='0'; 38 | python Embedder_0.py xmen_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/xmen/Embed_0/" 39 | 40 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/runner.sh: -------------------------------------------------------------------------------- 1 | xmen="/media/My Passport/Anthony/Steganography/Frames/xmen/"; 2 | dragon="/media/My Passport/Anthony/Steganography/Frames/dragon/"; 3 | captain="/media/My Passport/Anthony/Steganography/Frames/captain_america/"; 4 | spider="/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/"; 5 | 6 | additional="Original/*.bmp" 7 | 8 | ls "$xmen"$additional > xmen_filenames.txt 9 | ls "$captain"$additional > dragon_filenames.txt 10 | ls "$captain"$additional > captain_america_filenames.txt 11 | ls "$spider"$additional > spiderman_trailer_2_filenames.txt 12 | 13 | 14 | echo "DRAGON"; 15 | export PYOPENCL_CTX='0'; 16 | python Embedder_1.py dragon_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/dragon/Embed_1/" 17 | export PYOPENCL_CTX='0'; 18 | python Embedder_0.py dragon_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/dragon/Embed_0/" 19 | 20 | 21 | echo "SPIDERMAN"; 22 | export PYOPENCL_CTX='0'; 23 | python Embedder_1.py spiderman_trailer_2_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/Embed_1/" 24 | export PYOPENCL_CTX='0'; 25 | python Embedder_0.py spiderman_trailer_2_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/spiderman_trailer_2/Embed_0/" 26 | 27 | 28 | echo "captain_america"; 29 | export PYOPENCL_CTX='0'; 30 | python Embedder_1.py captain_america_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/captain_america/Embed_1/" 31 | export PYOPENCL_CTX='0'; 32 | python Embedder_0.py captain_america_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/captain_america/Embed_0/" 33 | 34 | echo "xmen"; 35 | export PYOPENCL_CTX='0'; 36 | python Embedder_1.py xmen_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/xmen/Embed_1/" 37 | export PYOPENCL_CTX='0'; 38 | python Embedder_0.py xmen_filenames.txt "/media/My Passport/Anthony/Steganography/Frames/xmen/Embed_0/" 39 | 40 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/detector_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import json 4 | import decoder as detector 5 | 6 | class DoDetection(tornado.web.RequestHandler): 7 | loader = template.Loader('./web') 8 | def post(self): 9 | print "Gonna do detection" 10 | print "recieved %d files " % len(self.request.files) 11 | 12 | recorded_file = self.request.files['recorded_file'][0]['body'].strip() 13 | original_file = self.request.files['original_file'][0]['body'].strip() 14 | 15 | name = self.request.files['original_file'][0]['filename'].strip() 16 | 17 | if 'spidey' in name: 18 | name = 'spidey' 19 | 20 | 21 | recorded_luma = eval(recorded_file) 22 | original_luma = eval(original_file) 23 | 24 | min_robustness = int(self.get_argument('min_robustness').strip()) 25 | bucket_size = int(self.get_argument('bucket_size').strip()) 26 | normal_size = int(self.get_argument('normal_size').strip()) 27 | bitstring_size = int(self.get_argument('bitstring_size').strip()) 28 | 29 | 30 | data = {'bucket_size': bucket_size, 'min_robustness_count': min_robustness, 31 | 'normal_size': normal_size, 'bitstring_size': bitstring_size, 32 | 'name': name} 33 | 34 | print "%d %d %d %d" % (min_robustness, bucket_size, normal_size, bitstring_size) 35 | 36 | # do the bitstring stuff 37 | bitstring_result = detector.main_decoder(data, original_luma, recorded_luma) 38 | html = self.loader.load('detector.html').generate(bitstring=bitstring_result) 39 | 40 | 41 | self.write(html) 42 | 43 | 44 | class DetectorHandler(tornado.web.RequestHandler): 45 | loader = template.Loader('./web') 46 | def post(self): 47 | print "got request for detector" 48 | html = self.loader.load('detector.html').generate(bitstring=None) 49 | data = json.dumps({'html': html}) 50 | self.write(data) 51 | 52 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/transformations.py: -------------------------------------------------------------------------------- 1 | from os.path import splitext as _splitext 2 | 3 | def _load_data(filename): 4 | fp = open(filename) 5 | data = fp.read() 6 | values = eval(data) 7 | fp.close() 8 | return values 9 | 10 | def _store_data(values=[], filename="/tmp/filename"): 11 | fp = open(filename, "w") 12 | fp.write("%s" % repr(values)) 13 | fp.close() 14 | 15 | def differential(filename): 16 | ''' 17 | computes x[i+1] - x[i] 18 | ''' 19 | 20 | values = _load_data(filename) 21 | 22 | difference_list = [] 23 | for i in xrange(1, len(values)): 24 | # x2 - x1 25 | difference_list.append(values[i] - values[i-1]) 26 | 27 | filename, extension = _splitext(filename) 28 | filename = filename + "_d" + extension 29 | 30 | _store_data(difference_list, filename) 31 | return filename 32 | 33 | def mean(filename): 34 | ''' 35 | computes x[i] - mean(x) 36 | ''' 37 | 38 | values = _load_data(filename) 39 | 40 | mean = sum(values) / len(values) 41 | 42 | mean_list = [] 43 | for i in values: 44 | mean_list.append(i - mean) 45 | 46 | filename, extension = _splitext(filename) 47 | filename = filename + "_mean" + extension 48 | 49 | _store_data(mean_list, filename) 50 | return filename 51 | 52 | def normalize(filename): 53 | ''' 54 | normalizes the graph to a certain range 55 | TODO: make the normalization relative to two graphs 56 | ''' 57 | values = _load_data(filename) 58 | max_val = max(values) 59 | min_val = min(values) 60 | 61 | normalized_list = [] 62 | for i in values: 63 | normalized_list.append( (float(i - min_val) / (max_val - min_val)) * 100) 64 | 65 | filename, extension = _splitext(filename) 66 | filename = filename + "_normalized" + extension 67 | 68 | _store_data(normalized_list, filename) 69 | return filename 70 | 71 | def std_dev(filename): 72 | ''' 73 | computes x[i] - standard_deviation 74 | ''' 75 | #TODO complete.. 76 | 77 | -------------------------------------------------------------------------------- /steganography_ui/web/embedder.html: -------------------------------------------------------------------------------- 1 |
    2 |

    EMBEDDER

    3 |
    4 |

    It takes all the frames from a folder of a video, and produces three folders - Normal, Zero and One Folder

    5 |

    This is a preprocessing step before joiner creates the stego video.

    6 |

    Unfortunately, this server does not have a GPU to support creating the zero one and normal folder, as it takes 34 seconds per Frame

    7 |

    A two minute video as 3000 frames !

    8 | 9 | 10 |
    11 |
    12 |

    Folder layout

    13 | 14 |
    15 | 16 |
    17 |

    embed 1 frames

    18 | 19 |
    20 | 21 |
    22 |

    embed 0 frames

    23 | 24 |
    25 |
    26 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 |
    33 | 34 |
    35 |
    36 | 37 |
    38 |
    39 | 40 |
    41 |
    42 |
    43 |
    44 |
    45 | 46 |
    47 | 48 |
    49 |

    Original Image

    50 | 51 |
    52 | 53 |
    54 |

    Increased Luma

    55 | 56 |
    57 | 58 |
    59 |

    Decreased Luma

    60 | 61 |
    62 | 63 |
    64 | 65 |
    66 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/transformation_handler.py: -------------------------------------------------------------------------------- 1 | from tornado import template 2 | import tornado.web 3 | import json 4 | import glob 5 | from custom_utils import * 6 | import plotter 7 | 8 | class TransformationHandler(tornado.web.RequestHandler): 9 | loader = template.Loader('./web') 10 | def post(self): 11 | documents = self.get_argument('documents', None) 12 | transformation = self.get_argument('transformation', None) 13 | num_selects = self.get_argument('num_selects', None) 14 | 15 | if not documents: 16 | self.finish(json.dumps({"error": "missing docs"})) 17 | return 18 | 19 | recieved_documents = json.loads(documents) 20 | 21 | if transformation not in AVAILABLE_TRANSFORMATIONS: 22 | self.finish(json.dumps({"error": "unknown transformation"})) 23 | return 24 | 25 | transform = getattr(transformations, transformation) 26 | documents = [] 27 | 28 | for document in recieved_documents: 29 | doc = glob.glob('uploads/%s' % document['name']) 30 | if not doc: 31 | documents.append(file_not_found(document['name'])) 32 | continue 33 | 34 | if not renderable_as_graph(document['name']): 35 | documents.append(file_not_supported(document['name'])) 36 | continue 37 | 38 | filename = document['name'] 39 | transformed_name = transform('uploads/%s' % filename) 40 | image_name, ext = os.path.splitext(os.path.basename(transformed_name)) 41 | plotter.plotter(transformed_name, 'images/%s.png' % image_name) 42 | data = {'name': os.path.basename(transformed_name), 'image_link': 'images/%s.png' % image_name, 'compatiable': True} 43 | documents.append(data) 44 | 45 | data = self.loader.load('transformed_rows.html').generate(documents=documents, operations=AVAILABLE_TRANSFORMATIONS, num_selects=num_selects) 46 | data = json.dumps({'html': data}) 47 | self.finish(data) 48 | 49 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/compare_files_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | from tornado import template 3 | import os 4 | import json 5 | import glob 6 | import plotter 7 | from custom_utils import * 8 | 9 | 10 | class CompareFilesHandler(tornado.web.RequestHandler): 11 | loader = template.Loader('./web') 12 | def post(self): 13 | print "got request to compare files" 14 | 15 | # get arguments 16 | files_to_compare = self.get_argument('files', default=None) 17 | num_selects = self.get_argument('num_selects', default=0) 18 | 19 | if not files_to_compare: 20 | data = json.dumps({'html': '
    no files selected
    '}) 21 | self.write(data) 22 | return 23 | 24 | files_to_compare = [i.strip() for i in files_to_compare.split(',')] 25 | files_to_compare = [i for i in files_to_compare if i != ''] 26 | 27 | documents = [] 28 | 29 | for _file in files_to_compare: 30 | files_with_prefix = glob.glob('uploads/%s' % _file) 31 | if not files_with_prefix: 32 | documents.append(file_not_found(_file)) 33 | continue 34 | 35 | if not renderable_as_graph(_file): 36 | documents.append(file_not_supported(_file)) 37 | continue 38 | 39 | documents.append(file_supported(_file)) 40 | 41 | # generate images for them 42 | for document in documents: 43 | if not document['compatiable']: 44 | document['image_link'] = '/images/not_found.jpg' 45 | continue 46 | 47 | images = map(os.path.basename, glob.glob('images/*.png')) 48 | images = [i[:-4] for i in images] 49 | 50 | name, ext = os.path.splitext(document['name']) 51 | if name not in images: 52 | # plotting it 53 | plotter.plotter('uploads/%s' % document['name'], 'images/%s' % (name + '.png')) 54 | 55 | document['image_link'] = '/images/%s' % (name + '.png') 56 | 57 | operations = AVAILABLE_TRANSFORMATIONS 58 | col_width = 90.0 / len(documents) 59 | 60 | html = self.loader.load('compare.html').generate(documents=documents, operations=operations, col_width=col_width, num_selects=num_selects) 61 | 62 | data = json.dumps({'html': html}) 63 | self.write(data) 64 | 65 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/cpu_embedder_slow/newest_embedder.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import Image 4 | import numpy as np 5 | import scipy.ndimage 6 | 7 | def embed_in_frame(current_img, prev_img, bit): 8 | w, h = current_img.size 9 | 10 | mu_min = 1 11 | laplacian_matrix = np.array([[-1, -1, -1], [-1, -8, -1], [-1, -1, -1]]) 12 | s = 0.025 13 | 14 | cur_img_arr = np.asarray(current_img) 15 | prev_img_arr = np.asarray(prev_img) 16 | 17 | lap_cur_img_arr = cur_img_arr.copy() 18 | scipy.ndimage.filters.laplace(cur_img_arr, lap_cur_img_arr) 19 | lap_cur_img_arr = s * lap_cur_img_arr 20 | 21 | _min = 10000 22 | _max = -9999 23 | 24 | for i in xrange(h): 25 | for j in xrange(w): 26 | abs_diff = int(cur_img_arr[i][j][0]) - int(prev_img_arr[i][j][0]) 27 | abs_diff = abs(abs_diff) 28 | 29 | mu = mu_min + abs_diff 30 | v = min(mu, lap_cur_img_arr[i][j][0]) 31 | 32 | if v < _min: _min = v 33 | if v > _max: _max = v 34 | 35 | if bit == 0: v = -v 36 | new_val = cur_img_arr[i][j][0] + v 37 | 38 | if new_val < 0: new_val = 0 39 | elif new_val > 255: new_val = 255 40 | 41 | cur_img_arr[i][j].put([0], new_val) 42 | 43 | print "Min: %d max: %d" % (_min, _max) 44 | return Image.fromarray(cur_img_arr, "YCbCr").convert("RGB") 45 | 46 | 47 | def main(): 48 | frame_text_file = sys.argv[1] 49 | output_folder = sys.argv[2] 50 | bit = sys.argv[3] 51 | 52 | if bit == '1': bit = 1 53 | else: bit = 0 54 | 55 | frame_list = open(frame_text_file).read().strip() 56 | frame_list = [i for i in frame_list.split('\n')] 57 | frame_list = [i for i in frame_list if i != ''] 58 | 59 | prev_img = Image.open(frame_list[0]) 60 | ycb_prev_img = prev_img.convert('YCbCr') 61 | 62 | for frame_name in frame_list: 63 | name, ext = os.path.splitext(os.path.basename(frame_name)) 64 | output_name = os.path.join(output_folder, name + ("embed_%d" % bit) + ext) 65 | 66 | current_img = Image.open(frame_name) 67 | ycb_current_img = current_img.convert('YCbCr') 68 | 69 | new_img = embed_in_frame(ycb_current_img, ycb_prev_img, bit) 70 | new_img.save(output_name) 71 | 72 | prev_img = current_img 73 | ycb_prev_img = ycb_current_img 74 | 75 | 76 | if __name__ == '__main__': 77 | if len(sys.argv) != 4: 78 | print "Wrong usage" 79 | print "filename, outputdir, bit" 80 | else: 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /steganography_ui/web/splitter.html: -------------------------------------------------------------------------------- 1 |
    2 |

    SPLITTER

    3 | 4 |

    Given a video, it will split it into frames. A frame rate can optionally be given

    5 | 6 |
    7 | 8 |
    9 |

    Original Video Split

    10 | 11 |
    12 |
    13 | 14 |
    15 |
    16 |
    17 |

    Here is the code

    18 | 19 |
    20 |         #!/usr/bin/env bash
    21 |         filename=$(basename "$1");
    22 |         extension="${filename##*.}";
    23 |         filename="${filename%.*}";
    24 |         pretty_separator="-----------------------------------------------------------------------";
    25 | 
    26 | 
    27 |         if [[ -z "$1" ]]; then
    28 |             echo "Usage: ./anto_script.sh video_file [framerate=25]"
    29 |             exit;
    30 |         fi
    31 |         if [[ -z "$2" ]]; then
    32 |             frame_rate=25;
    33 |         else
    34 |             frame_rate=$2;
    35 |         fi
    36 | 
    37 |         echo $pretty_separator;
    38 |         image_dir="images_$filename";
    39 |         if [ -d "$image_dir" ]; then
    40 |             echo "Directory $image_dir already exists";
    41 |             read -p "Delete directory and continue Y/n? " -n 1 -r
    42 |             echo    # (optional) move to a new line
    43 |             if [[ $REPLY =~ ^[Yy]$ ]]
    44 |             then
    45 |                 # do dangerous stuff
    46 |                 rm -rf $image_dir;
    47 |             else
    48 |                 echo "remove and run this again ";
    49 |                 exit;
    50 |             fi
    51 |         fi
    52 |         echo "creating $image_dir";
    53 |         mkdir $image_dir;
    54 | 
    55 |         echo "running ffmpeg on $filename storing images in $image_dir, modify script to change framerate, default $frame_rate";
    56 |         echo $pretty_separator;
    57 | 
    58 |         ffmpeg -i $1 -r $frame_rate -f image2 $image_dir/image_%08d.bmp;
    59 | 
    60 |         echo $pretty_separator;
    61 | 
    62 |         ls -d -1 $PWD/$image_dir/*.bmp  > $image_dir/filenames.txt;
    63 |         echo "calling calc_luminance.py on the images, saved at $image_dir/luminance_values";
    64 |         python calc_luminance.py $image_dir/filenames.txt > $image_dir/luminance_values.repr ;
    65 | 
    66 |         echo $pretty_separator;
    67 | 
    68 |         echo "Creating graph and saving in $image_dir/luminance_values.repr.bmp";
    69 |         python plotter.py $image_dir/luminance_values.repr ;
    70 | # eog $image_dir/luminance_values.repr.bmp;
    71 |         echo "done";
    72 |         
    73 |
    74 |
    75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Video-Steganography-for-Piracy-Prevention 2 | 3 | Video Steganography and Digital Watermarking are domains of Computer Science that 4 | deal with data confidentiality and aim to hide information inside a video, such that it is hidden 5 | in plain sight, but retrievable only by the intended user. Thus they can be used for digital 6 | copyrighting of videos and tackling video piracy, which has become a huge problem in the 7 | entertainment industry. It is reported that the movie industry loses $25 billion a year to it. There 8 | are several companies that offer Direct to Home (DTH) video such as Netflix, Hulu, which 9 | allow viewers to stream and view movies and TV shows on their websites. While there is 10 | current technology to prevent direct screen capture, there is no check to prevent video recording 11 | using an external device. Since the paid websites like Netflix keep account and banking details 12 | of each movie transaction, it becomes easy to track the person buying the movie. Thus by 13 | embedding information unique to a transaction (a transaction identifier) into the video using 14 | video steganography techniques, and the retrieval of the same from any pirated or recreated 15 | copy of that video, it is possible to identify the video pirate. 16 | 17 | 18 | A 64 bit unique transaction identifier is embedded into every movie by altering the 19 | luminance values of the frames of the video, which persists through recordings and corruption, 20 | and thus each viewer of a video is served a unique copy of that video. Thus any recording of 21 | that video can still be traced back to the owner. A bit value of 1 is represented by an increase, 22 | and 0 by a decrease in the luminance of the frame based on global and local factors of the pixels 23 | of that frame. The transaction identifier is embedded across multiple frames and multiple times 24 | in order to achieve robustness and survive any intentional and unintentional attacks to corrupt 25 | the data. Thus a steganography system is developed using Python and harnesses the power of 26 | the GPU using OpenCL, and built in Ubuntu 13.04. 27 | 28 | 29 | This novel steganography algorithm is successful in its approach towards embedding 30 | and detecting data in videos of duration 2 minutes or more. A 100% accuracy of embedding 31 | and extraction of a 32-bit string is achieved, and a correspondence factor of 87.19% between 32 | the original video and recording is obtained. The degree of robustness depends on the nature 33 | and length of the video, but high repetition could degrade the video quality, and thus a middle 34 | ground is to be achieved. The system developed provides a great base towards video piracy 35 | prevention and opens up avenues for further research and development. 36 | -------------------------------------------------------------------------------- /steganography_ui/modules/calc_luminance/gpu_code/gpu_calc_luma.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy 3 | import Image 4 | import time 5 | import os 6 | from humanize import naturalsize, naturaltime 7 | import sys 8 | 9 | if len(sys.argv) >= 4: 10 | target_dir = sys.argv[2] 11 | target_name = sys.argv[3] 12 | else: 13 | print "give a target_dir" 14 | sys.exit() 15 | 16 | 17 | output_file = open('%s' % (os.path.join(target_dir, target_name)), 'w') 18 | output_file.write('hello') 19 | 20 | ACTUAL_START_TIME = time.time() 21 | 22 | img_names_file = sys.argv[1] 23 | img_names = open(img_names_file).read() 24 | img_names_total = [i.strip() for i in img_names.split('\n') if i.strip() != ''] 25 | 26 | numpy.set_printoptions(threshold=numpy.nan) 27 | 28 | while img_names_total: 29 | img_names = img_names_total[:20] 30 | img_names_total = img_names_total[20:] 31 | print "processing ", img_names 32 | if not img_names: 33 | break 34 | 35 | if len(img_names) > 20: 36 | print "Only 20 aloud" 37 | sys.exit() 38 | 39 | img1 = Image.open(img_names[0]) 40 | width, height = img1.size 41 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 42 | imgsize = img_arr.nbytes 43 | dim = img_arr.shape 44 | host_arr = img_arr.reshape(-1); 45 | 46 | for name in img_names[1:]: 47 | img1 = Image.open(name) 48 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 49 | host_arr = numpy.concatenate((host_arr, img_arr.reshape(-1))); 50 | 51 | host_arr = host_arr.astype(numpy.uint8) 52 | print dim 53 | new_dim = (len(img_names), dim[0], dim[1], dim[2]) 54 | print "new dimensions are", new_dim 55 | 56 | ctx = cl.create_some_context() 57 | queue = cl.CommandQueue(ctx) 58 | mf = cl.mem_flags 59 | a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=host_arr) 60 | 61 | luma_values_array = numpy.zeros((len(img_names), ), dtype=numpy.long) 62 | dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, luma_values_array.nbytes) 63 | 64 | 65 | print "[%d] Takes " % len(img_names) , naturalsize(luma_values_array.nbytes) 66 | 67 | kernel_code = open("calc_luma.cl").read() % (new_dim[1], new_dim[2], new_dim[3]) 68 | prg1 = cl.Program(ctx, kernel_code).build() 69 | 70 | stime = time.time() 71 | prg1.calc_luma(queue, (len(img_names),) , None, a_buf, dest_buf) 72 | etime = time.time() 73 | 74 | print "[%d] GPU takes " % len(img_names), naturaltime(etime - stime) 75 | 76 | cl.enqueue_copy(queue, luma_values_array, dest_buf) 77 | 78 | # result is a array of all images combined 79 | _index = 0 80 | size_slice = imgsize 81 | 82 | stime = time.time() 83 | print "Writing to file" 84 | for i in xrange(len(img_names)): 85 | output_file.write("%f\n" % (float(luma_values_array[i])/ (1920 * 1080))) 86 | 87 | etime = time.time() 88 | 89 | print "[%d] Saving takes " % len(img_names), naturaltime(etime - stime) 90 | print "done" 91 | ACTUAL_END_TIME = time.time() 92 | print "Took %s " % naturaltime(ACTUAL_END_TIME - ACTUAL_START_TIME) 93 | 94 | output_file.close() 95 | -------------------------------------------------------------------------------- /Embedder/Embedder_0.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy 3 | import Image 4 | import time 5 | import os 6 | from humanize import naturalsize, naturaltime 7 | import sys 8 | 9 | if len(sys.argv) >= 3: 10 | target_dir = sys.argv[2] 11 | else: 12 | print "give a target_dir" 13 | sys.exit() 14 | 15 | 16 | ACTUAL_START_TIME = time.time() 17 | 18 | img_names_file = sys.argv[1] 19 | img_names = open(img_names_file).read() 20 | img_names_total = [i.strip() for i in img_names.split('\n') if i.strip() != ''] 21 | 22 | numpy.set_printoptions(threshold=numpy.nan) 23 | for step in xrange(300): 24 | img_names = img_names_total[step*20: (step+1)*20] 25 | if not img_names: 26 | break 27 | if len(img_names) > 20: 28 | print "Only 20 aloud" 29 | sys.exit() 30 | 31 | img1 = Image.open(img_names[0]) 32 | # new 33 | # img1 = img.convert("YCbCr") 34 | # end all img changed to img1 35 | width, height = img1.size 36 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 37 | imgsize = img_arr.nbytes 38 | dim = img_arr.shape 39 | host_arr = img_arr.reshape(-1); 40 | 41 | for name in img_names[1:]: 42 | img1 = Image.open(name) 43 | # img1 = img.convert("YCbCr") 44 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 45 | 46 | host_arr = numpy.concatenate((host_arr, img_arr.reshape(-1))); 47 | 48 | host_arr = host_arr.astype(numpy.uint8) 49 | print dim 50 | new_dim = (len(img_names), dim[0], dim[1], dim[2]) 51 | print "new dimensions are", new_dim 52 | 53 | ctx = cl.create_some_context() 54 | queue = cl.CommandQueue(ctx) 55 | mf = cl.mem_flags 56 | a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=host_arr) 57 | dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, host_arr.nbytes) 58 | 59 | 60 | print "[%d] Takes " % len(img_names) , naturalsize(host_arr.nbytes) 61 | 62 | kernel_code = open("embed_0.cl").read() % (new_dim[1], new_dim[2], new_dim[3]) 63 | prg1 = cl.Program(ctx, kernel_code).build() 64 | 65 | stime = time.time() 66 | prg1.embed_zero(queue, (new_dim[0], new_dim[1], new_dim[2]) , None, a_buf, dest_buf) 67 | etime = time.time() 68 | 69 | print "[%d] GPU takes " % len(img_names), naturaltime(etime - stime) 70 | 71 | result = numpy.empty_like(host_arr) 72 | cl.enqueue_copy(queue, result, dest_buf) 73 | 74 | # result is a array of all images combined 75 | _index = 0 76 | size_slice = imgsize 77 | 78 | stime = time.time() 79 | for name in img_names: 80 | img_arr = result[_index * size_slice: (_index +1 )* size_slice] 81 | img_arr = img_arr.reshape(dim) 82 | img2 = Image.fromarray(img_arr) 83 | name, ext = os.path.splitext(name) 84 | name = os.path.basename(name) 85 | name = name + "embed_zero.bmp" 86 | img2.save(os.path.join(target_dir, name)) 87 | _index += 1 88 | 89 | etime = time.time() 90 | 91 | print "[%d] Saving takes " % len(img_names), naturaltime(etime - stime) 92 | print "done" 93 | ACTUAL_END_TIME = time.time() 94 | print "Took %s " % naturaltime(ACTUAL_END_TIME - ACTUAL_START_TIME) 95 | -------------------------------------------------------------------------------- /Embedder/Embedder_1.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy 3 | import Image 4 | import time 5 | import os 6 | from humanize import naturalsize, naturaltime 7 | import sys 8 | 9 | if len(sys.argv) >= 3: 10 | target_dir = sys.argv[2] 11 | else: 12 | print "give a target_dir" 13 | sys.exit() 14 | 15 | ACTUAL_START_TIME = time.time() 16 | 17 | img_names_file = sys.argv[1] 18 | img_names = open(img_names_file).read() 19 | img_names_total = [i.strip() for i in img_names.split('\n') if i.strip() != ''] 20 | 21 | numpy.set_printoptions(threshold=numpy.nan) 22 | 23 | for step in xrange(300): 24 | img_names = img_names_total[step*20: (step+1) * 20] 25 | if not img_names: 26 | break 27 | 28 | if len(img_names) > 20: 29 | print "Only 20 aloud" 30 | sys.exit() 31 | 32 | img1 = Image.open(img_names[0]) 33 | # new 34 | # img1 = img.convert("YCbCr") 35 | # end all img changed to img1 36 | width, height = img1.size 37 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 38 | imgsize = img_arr.nbytes 39 | dim = img_arr.shape 40 | host_arr = img_arr.reshape(-1); 41 | 42 | for name in img_names[1:]: 43 | img1 = Image.open(name) 44 | # img1 = img.convert("YCbCr") 45 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 46 | 47 | host_arr = numpy.concatenate((host_arr, img_arr.reshape(-1))); 48 | 49 | host_arr = host_arr.astype(numpy.uint8) 50 | print dim 51 | new_dim = (len(img_names), dim[0], dim[1], dim[2]) 52 | print "new dimensions are", new_dim 53 | 54 | ctx = cl.create_some_context() 55 | queue = cl.CommandQueue(ctx) 56 | mf = cl.mem_flags 57 | a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=host_arr) 58 | dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, host_arr.nbytes) 59 | 60 | 61 | print "[%d] Takes " % len(img_names) , naturalsize(host_arr.nbytes) 62 | 63 | kernel_code = open("embed_1.cl").read() % (new_dim[1], new_dim[2], new_dim[3]) 64 | prg1 = cl.Program(ctx, kernel_code).build() 65 | 66 | stime = time.time() 67 | prg1.embed_one(queue, (new_dim[0], new_dim[1], new_dim[2]) , None, a_buf, dest_buf) 68 | etime = time.time() 69 | 70 | print "[%d] GPU takes " % len(img_names), naturaltime(etime - stime) 71 | 72 | result = numpy.empty_like(host_arr) 73 | cl.enqueue_copy(queue, result, dest_buf) 74 | 75 | # result is a array of all images combined 76 | _index = 0 77 | size_slice = imgsize 78 | 79 | stime = time.time() 80 | for name in img_names: 81 | img_arr = result[_index * size_slice: (_index +1 )* size_slice] 82 | img_arr = img_arr.reshape(dim) 83 | img2 = Image.fromarray(img_arr) 84 | name, ext = os.path.splitext(name) 85 | name = os.path.basename(name) 86 | name = name + "embed_one.bmp" 87 | img2.save(os.path.join(target_dir, name)) 88 | _index += 1 89 | 90 | etime = time.time() 91 | 92 | print "[%d] Saving takes " % len(img_names), naturaltime(etime - stime) 93 | print "done" 94 | ACTUAL_END_TIME = time.time() 95 | print "Took %s " % naturaltime(ACTUAL_END_TIME - ACTUAL_START_TIME) 96 | -------------------------------------------------------------------------------- /steganography_ui/modules/decoder/decoder.py: -------------------------------------------------------------------------------- 1 | #take input of two .repr files of luma, output the embedded code in them 2 | import os 3 | import sys 4 | from collections import Counter 5 | 6 | BUCKET_SIZE = 8 7 | BITSTRING_SIZE = 8 8 | NORMAL_SIZE = 25 9 | MIN_ROBUSTNESS_COUNT = 6 10 | 11 | def get_embedded_string_from_bitstring(input_str, ROBUSTNESS_DEGREE): 12 | robustness_arr = [] 13 | for i in xrange(ROBUSTNESS_DEGREE): 14 | bitstring = input_str[i*BITSTRING_SIZE*BUCKET_SIZE:(i+1)*BITSTRING_SIZE*BUCKET_SIZE] 15 | bit_arr = [] 16 | for j in xrange(BITSTRING_SIZE): 17 | bit = bitstring[j*BUCKET_SIZE:(j+1)*BUCKET_SIZE] 18 | if not bit: 19 | print "%dth iteration" % j 20 | print "j * bitstring size = "% (j * BITSTRING_SIZE) 21 | the_bit = max([(v,k) for k,v in Counter(bit).items()])[-1] 22 | bit_arr.append(the_bit) 23 | robustness_arr.append(bit_arr) 24 | 25 | robustness_arr = zip(*robustness_arr) 26 | 27 | final_output = '' 28 | for i in robustness_arr: 29 | the_bit = max([(v,k) for k,v in Counter(i).items()])[-1] 30 | final_output += the_bit 31 | 32 | 33 | return final_output 34 | 35 | def sufficient_frames(list_normal_files, list_recording_files): 36 | number_embed_frames = (2 * NORMAL_SIZE) + BUCKET_SIZE * BITSTRING_SIZE * MIN_ROBUSTNESS_COUNT 37 | print "Number of embed frames required is %d " % number_embed_frames 38 | if len(list_normal_files) > number_embed_frames: return True 39 | if len(list_recording_files) > number_embed_frames: return True 40 | 41 | def find_robustness_degree(list_normal_files, list_recording_files): 42 | number_embed_frames = min(len(list_normal_files), len(list_recording_files)) 43 | number_robust_embed_frames = number_embed_frames - (2 * NORMAL_SIZE) 44 | robustness_degree = number_robust_embed_frames / (BUCKET_SIZE * BITSTRING_SIZE) 45 | return int(robustness_degree) 46 | 47 | def main(): 48 | 49 | fp_normal = open(sys.argv[1]) 50 | fp_recording = open(sys.argv[2]) 51 | list_normal_files = eval(fp_normal.read()) 52 | list_recording_files = eval(fp_recording.read()) 53 | 54 | if not sufficient_frames(list_normal_files, list_recording_files): 55 | print "Insufficient frames" 56 | return 57 | robustness_degree = find_robustness_degree(list_normal_files, list_recording_files) 58 | 59 | #may need to put a sync between the two lists, but for now assuming that both are perfectly synced and keeping only equal elements 60 | len_frames = min(len(list_normal_files), len(list_recording_files)) 61 | list_normal_files = list_normal_files[:len_frames] 62 | list_recording_files = list_recording_files[:len_frames] 63 | 64 | #trimming the normal frames from both 65 | list_normal_files = list_normal_files[NORMAL_SIZE: len(list_normal_files) - NORMAL_SIZE] 66 | list_recording_files = list_recording_files[NORMAL_SIZE: len(list_recording_files) - NORMAL_SIZE] 67 | 68 | embedded_data = "" 69 | for i,j in zip(list_normal_files, list_recording_files): 70 | if i > j: embedded_data += '0' 71 | elif i < j: embedded_data += '1' 72 | 73 | print get_embedded_string_from_bitstring(embedded_data, robustness_degree) 74 | 75 | if __name__ == '__main__': 76 | if len(sys.argv) != 3: 77 | print "Wrong Usage" 78 | else: 79 | main() 80 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/Embedder_0.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy 3 | import Image 4 | import time 5 | import os 6 | from humanize import naturalsize, naturaltime 7 | import sys 8 | 9 | if len(sys.argv) >= 3: 10 | target_dir = sys.argv[2] 11 | else: 12 | print "give a target_dir" 13 | sys.exit() 14 | 15 | 16 | ACTUAL_START_TIME = time.time() 17 | 18 | img_names_file = sys.argv[1] 19 | img_names = open(img_names_file).read() 20 | img_names_total = [i.strip() for i in img_names.split('\n') if i.strip() != ''] 21 | 22 | numpy.set_printoptions(threshold=numpy.nan) 23 | for step in xrange(300): 24 | img_names = img_names_total[step*20: (step+1)*20] 25 | if not img_names: 26 | break 27 | if len(img_names) > 20: 28 | print "Only 20 aloud" 29 | sys.exit() 30 | 31 | img1 = Image.open(img_names[0]) 32 | # new 33 | # img1 = img.convert("YCbCr") 34 | # end all img changed to img1 35 | width, height = img1.size 36 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 37 | imgsize = img_arr.nbytes 38 | dim = img_arr.shape 39 | host_arr = img_arr.reshape(-1); 40 | 41 | for name in img_names[1:]: 42 | img1 = Image.open(name) 43 | # img1 = img.convert("YCbCr") 44 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 45 | 46 | host_arr = numpy.concatenate((host_arr, img_arr.reshape(-1))); 47 | 48 | host_arr = host_arr.astype(numpy.uint8) 49 | print dim 50 | new_dim = (len(img_names), dim[0], dim[1], dim[2]) 51 | print "new dimensions are", new_dim 52 | 53 | ctx = cl.create_some_context() 54 | queue = cl.CommandQueue(ctx) 55 | mf = cl.mem_flags 56 | a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=host_arr) 57 | dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, host_arr.nbytes) 58 | 59 | 60 | print "[%d] Takes " % len(img_names) , naturalsize(host_arr.nbytes) 61 | 62 | kernel_code = open("embed_0.cl").read() % (new_dim[1], new_dim[2], new_dim[3]) 63 | prg1 = cl.Program(ctx, kernel_code).build() 64 | 65 | stime = time.time() 66 | prg1.embed_zero(queue, (new_dim[0], new_dim[1], new_dim[2]) , None, a_buf, dest_buf) 67 | etime = time.time() 68 | 69 | print "[%d] GPU takes " % len(img_names), naturaltime(etime - stime) 70 | 71 | result = numpy.empty_like(host_arr) 72 | cl.enqueue_copy(queue, result, dest_buf) 73 | 74 | # result is a array of all images combined 75 | _index = 0 76 | size_slice = imgsize 77 | 78 | stime = time.time() 79 | for name in img_names: 80 | img_arr = result[_index * size_slice: (_index +1 )* size_slice] 81 | img_arr = img_arr.reshape(dim) 82 | img2 = Image.fromarray(img_arr) 83 | name, ext = os.path.splitext(name) 84 | name = os.path.basename(name) 85 | name = name + "embed_zero.bmp" 86 | img2.save(os.path.join(target_dir, name)) 87 | _index += 1 88 | 89 | etime = time.time() 90 | 91 | print "[%d] Saving takes " % len(img_names), naturaltime(etime - stime) 92 | print "done" 93 | ACTUAL_END_TIME = time.time() 94 | print "Took %s " % naturaltime(ACTUAL_END_TIME - ACTUAL_START_TIME) 95 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/Embedder_1.py: -------------------------------------------------------------------------------- 1 | import pyopencl as cl 2 | import numpy 3 | import Image 4 | import time 5 | import os 6 | from humanize import naturalsize, naturaltime 7 | import sys 8 | 9 | if len(sys.argv) >= 3: 10 | target_dir = sys.argv[2] 11 | else: 12 | print "give a target_dir" 13 | sys.exit() 14 | 15 | ACTUAL_START_TIME = time.time() 16 | 17 | img_names_file = sys.argv[1] 18 | img_names = open(img_names_file).read() 19 | img_names_total = [i.strip() for i in img_names.split('\n') if i.strip() != ''] 20 | 21 | numpy.set_printoptions(threshold=numpy.nan) 22 | 23 | for step in xrange(300): 24 | img_names = img_names_total[step*20: (step+1) * 20] 25 | if not img_names: 26 | break 27 | 28 | if len(img_names) > 20: 29 | print "Only 20 aloud" 30 | sys.exit() 31 | 32 | img1 = Image.open(img_names[0]) 33 | # new 34 | # img1 = img.convert("YCbCr") 35 | # end all img changed to img1 36 | width, height = img1.size 37 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 38 | imgsize = img_arr.nbytes 39 | dim = img_arr.shape 40 | host_arr = img_arr.reshape(-1); 41 | 42 | for name in img_names[1:]: 43 | img1 = Image.open(name) 44 | # img1 = img.convert("YCbCr") 45 | img_arr = numpy.asarray(img1).astype(numpy.uint8); 46 | 47 | host_arr = numpy.concatenate((host_arr, img_arr.reshape(-1))); 48 | 49 | host_arr = host_arr.astype(numpy.uint8) 50 | print dim 51 | new_dim = (len(img_names), dim[0], dim[1], dim[2]) 52 | print "new dimensions are", new_dim 53 | 54 | ctx = cl.create_some_context() 55 | queue = cl.CommandQueue(ctx) 56 | mf = cl.mem_flags 57 | a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=host_arr) 58 | dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, host_arr.nbytes) 59 | 60 | 61 | print "[%d] Takes " % len(img_names) , naturalsize(host_arr.nbytes) 62 | 63 | kernel_code = open("embed_1.cl").read() % (new_dim[1], new_dim[2], new_dim[3]) 64 | prg1 = cl.Program(ctx, kernel_code).build() 65 | 66 | stime = time.time() 67 | prg1.embed_one(queue, (new_dim[0], new_dim[1], new_dim[2]) , None, a_buf, dest_buf) 68 | etime = time.time() 69 | 70 | print "[%d] GPU takes " % len(img_names), naturaltime(etime - stime) 71 | 72 | result = numpy.empty_like(host_arr) 73 | cl.enqueue_copy(queue, result, dest_buf) 74 | 75 | # result is a array of all images combined 76 | _index = 0 77 | size_slice = imgsize 78 | 79 | stime = time.time() 80 | for name in img_names: 81 | img_arr = result[_index * size_slice: (_index +1 )* size_slice] 82 | img_arr = img_arr.reshape(dim) 83 | img2 = Image.fromarray(img_arr) 84 | name, ext = os.path.splitext(name) 85 | name = os.path.basename(name) 86 | name = name + "embed_one.bmp" 87 | img2.save(os.path.join(target_dir, name)) 88 | _index += 1 89 | 90 | etime = time.time() 91 | 92 | print "[%d] Saving takes " % len(img_names), naturaltime(etime - stime) 93 | print "done" 94 | ACTUAL_END_TIME = time.time() 95 | print "Took %s " % naturaltime(ACTUAL_END_TIME - ACTUAL_START_TIME) 96 | -------------------------------------------------------------------------------- /steganography_ui/modules/decoder/stuff/godzilla_package/godzilla_decoder.py: -------------------------------------------------------------------------------- 1 | #take input of two .repr files of luma, output the embedded code in them 2 | import os 3 | import sys 4 | from collections import Counter 5 | 6 | BUCKET_SIZE = 24 7 | BITSTRING_SIZE = 16 8 | NORMAL_SIZE = 100 9 | MIN_ROBUSTNESS_COUNT = 6 10 | 11 | def get_embedded_string_from_bitstring(input_str, ROBUSTNESS_DEGREE): 12 | robustness_arr = [] 13 | for i in xrange(ROBUSTNESS_DEGREE): 14 | bitstring = input_str[i*BITSTRING_SIZE*BUCKET_SIZE:(i+1)*BITSTRING_SIZE*BUCKET_SIZE] 15 | bit_arr = [] 16 | for j in xrange(BITSTRING_SIZE): 17 | bit = bitstring[j*BUCKET_SIZE:(j+1)*BUCKET_SIZE] 18 | if not bit: 19 | print "%d %d" % (i, j) 20 | break 21 | the_bit = max([(v,k) for k,v in Counter(bit).items()])[-1] 22 | bit_arr.append(the_bit) 23 | robustness_arr.append(bit_arr) 24 | 25 | robustness_arr = zip(*robustness_arr) 26 | 27 | final_output = '' 28 | for i in robustness_arr: 29 | the_bit = max([(v,k) for k,v in Counter(i).items()])[-1] 30 | final_output += the_bit 31 | 32 | 33 | return final_output 34 | 35 | def sufficient_frames(list_normal_files, list_recording_files): 36 | number_embed_frames = (2 * NORMAL_SIZE) + BUCKET_SIZE * BITSTRING_SIZE * MIN_ROBUSTNESS_COUNT 37 | print "Number of embed frames required is %d " % number_embed_frames 38 | if len(list_normal_files) > number_embed_frames: return True 39 | if len(list_recording_files) > number_embed_frames: return True 40 | 41 | def find_robustness_degree(list_normal_files, list_recording_files): 42 | number_embed_frames = min(len(list_normal_files), len(list_recording_files)) 43 | number_robust_embed_frames = number_embed_frames - (2 * NORMAL_SIZE) 44 | robustness_degree = number_robust_embed_frames / (BUCKET_SIZE * BITSTRING_SIZE) 45 | return int(robustness_degree) - 1 46 | 47 | def main(): 48 | 49 | fp_normal = open(sys.argv[1]) 50 | fp_recording = open(sys.argv[2]) 51 | list_normal_files = eval(fp_normal.read()) 52 | list_recording_files = eval(fp_recording.read()) 53 | 54 | if not sufficient_frames(list_normal_files, list_recording_files): 55 | print "Insufficient frames" 56 | return 57 | robustness_degree = find_robustness_degree(list_normal_files, list_recording_files) 58 | 59 | #may need to put a sync between the two lists, but for now assuming that both are perfectly synced and keeping only equal elements 60 | len_frames = min(len(list_normal_files), len(list_recording_files)) 61 | list_normal_files = list_normal_files[:len_frames] 62 | list_recording_files = list_recording_files[:len_frames] 63 | 64 | #trimming the normal frames from both 65 | list_normal_files = list_normal_files[NORMAL_SIZE: len(list_normal_files) - NORMAL_SIZE] 66 | list_recording_files = list_recording_files[NORMAL_SIZE: len(list_recording_files) - NORMAL_SIZE] 67 | 68 | print len(list_normal_files), len(list_recording_files) 69 | 70 | embedded_data = "" 71 | for i,j in zip(list_normal_files, list_recording_files): 72 | if i > j: embedded_data += '0' 73 | elif i < j: embedded_data += '1' 74 | 75 | print get_embedded_string_from_bitstring(embedded_data, 6) 76 | 77 | if __name__ == '__main__': 78 | if len(sys.argv) != 3: 79 | print "Wrong Usage" 80 | else: 81 | main() 82 | -------------------------------------------------------------------------------- /steganography_ui/web/overview_slide_.html: -------------------------------------------------------------------------------- 1 | 44 | -------------------------------------------------------------------------------- /Embedder/embed_1.cl: -------------------------------------------------------------------------------- 1 | int get_luma_index(int imgid, int nrows, int ncols, int npix, int x, int y) 2 | { 3 | return ((imgid * nrows * ncols * npix) + (x * ncols * npix) + (y * npix)); 4 | } 5 | 6 | int get_luma(int r, int g, int b){ 7 | int luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; 8 | return luma; 9 | } 10 | 11 | __kernel void embed_one(__global const uchar *a, __global uchar *c) 12 | { 13 | // embedding one bit into the image 14 | int imgid = get_global_id(0); 15 | int rowid = get_global_id(1); 16 | int colid = get_global_id(2); 17 | 18 | int nrows = %d; 19 | int ncols = %d; 20 | int npix = %d; 21 | 22 | int current_index = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 23 | 24 | float r, g, b; 25 | int _r, _g, _b; 26 | float y, cb, cr; 27 | r = a[current_index]; 28 | g = a[current_index + 1]; 29 | b = a[current_index + 2]; 30 | y = get_luma(r,g,b); 31 | cb = -0.09991 * r - 0.33609 * g + 0.436 * b; 32 | cr = 0.615 * r - 0.55861 * g -0.05639 * b; 33 | 34 | /* finding that value v */ 35 | int laplacian_sum = 0; 36 | 37 | int xm1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid-1); 38 | int x_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid-1); 39 | int xp1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid-1); 40 | 41 | int xm1_y = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid); 42 | int x_y = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 43 | int xp1_y = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid); 44 | 45 | int xm1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid+1); 46 | int x_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid+1); 47 | int xp1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid+1); 48 | 49 | laplacian_sum += 8 * a[x_y]; 50 | if( colid != 0 ) laplacian_sum -= a[xm1_y]; 51 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_y]; 52 | 53 | if( rowid != 0){ 54 | laplacian_sum -= a[x_ym1]; 55 | if( colid != 0 ) laplacian_sum -= a[xm1_ym1]; 56 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_ym1]; 57 | } 58 | 59 | if( rowid != (nrows - 1)){ 60 | laplacian_sum -= a[x_yp1]; 61 | if( colid != 0 ) laplacian_sum -= a[xm1_yp1]; 62 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_yp1]; 63 | } 64 | 65 | float laplacian_factor = 0.25f * (float)laplacian_sum; 66 | int l_value = (int)(laplacian_factor + 0.5); 67 | if(l_value < 0) l_value = -1 * l_value; 68 | 69 | int u_min = 3; 70 | int prev_img_luma_index = current_index; 71 | if(imgid != 0) prev_img_luma_index = get_luma_index(imgid-1, nrows, ncols, npix, rowid, colid); 72 | 73 | int prev_img_luma = get_luma(a[prev_img_luma_index], a[prev_img_luma_index + 1], a[prev_img_luma_index + 2]); 74 | int luma_diff = y - prev_img_luma; 75 | if( luma_diff < 0) luma_diff = -1 * luma_diff; 76 | 77 | int u = u_min + luma_diff; 78 | 79 | int v = (u < l_value)? u : l_value; 80 | 81 | /* found that value v */ 82 | if(v < 0) v = -1 * v; 83 | 84 | y = y + 8; 85 | if(y > 255) y = 255; 86 | 87 | r = y + 1.28033 * cr; 88 | g = y - 0.21482 * cb - 0.38059 * cr; 89 | b = y + 2.12798 * cb; 90 | 91 | _r = (int) r; 92 | _g = (int) g; 93 | _b = (int) b; 94 | 95 | if(_r > 255) _r = 255; 96 | if(_r < 0 ) _r = 0; 97 | 98 | if(_g > 255) _g = 255; 99 | if(_g < 0 ) _g = 0; 100 | 101 | if(_b > 255) _b = 255; 102 | if(_b < 0 ) _b = 0; 103 | 104 | c[current_index] = _r; 105 | c[current_index + 1] = _g; 106 | c[current_index + 2] = _b; 107 | } 108 | -------------------------------------------------------------------------------- /Embedder/embed_0.cl: -------------------------------------------------------------------------------- 1 | int get_luma_index(int imgid, int nrows, int ncols, int npix, int x, int y) 2 | { 3 | return ((imgid * nrows * ncols * npix) + (x * ncols * npix) + (y * npix)); 4 | } 5 | 6 | int get_luma(int r, int g, int b){ 7 | int luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; 8 | return luma; 9 | } 10 | 11 | __kernel void embed_zero(__global const uchar *a, __global uchar *c) 12 | { 13 | // embedding one bit into the image 14 | int imgid = get_global_id(0); 15 | int rowid = get_global_id(1); 16 | int colid = get_global_id(2); 17 | 18 | int nrows = %d; 19 | int ncols = %d; 20 | int npix = %d; 21 | 22 | int current_index = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 23 | 24 | float r, g, b; 25 | int _r, _g, _b; 26 | float y, cb, cr; 27 | r = a[current_index]; 28 | g = a[current_index + 1]; 29 | b = a[current_index + 2]; 30 | y = get_luma(r,g,b); 31 | cb = -0.09991 * r - 0.33609 * g + 0.436 * b; 32 | cr = 0.615 * r - 0.55861 * g -0.05639 * b; 33 | 34 | /* finding that value v */ 35 | int laplacian_sum = 0; 36 | 37 | int xm1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid-1); 38 | int x_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid-1); 39 | int xp1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid-1); 40 | 41 | int xm1_y = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid); 42 | int x_y = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 43 | int xp1_y = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid); 44 | 45 | int xm1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid+1); 46 | int x_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid+1); 47 | int xp1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid+1); 48 | 49 | laplacian_sum += 8 * a[x_y]; 50 | if( colid != 0 ) laplacian_sum -= a[xm1_y]; 51 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_y]; 52 | 53 | if( rowid != 0){ 54 | laplacian_sum -= a[x_ym1]; 55 | if( colid != 0 ) laplacian_sum -= a[xm1_ym1]; 56 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_ym1]; 57 | } 58 | 59 | if( rowid != (nrows - 1)){ 60 | laplacian_sum -= a[x_yp1]; 61 | if( colid != 0 ) laplacian_sum -= a[xm1_yp1]; 62 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_yp1]; 63 | } 64 | 65 | float laplacian_factor = 0.25f * (float)laplacian_sum; 66 | int l_value = (int)(laplacian_factor + 0.5); 67 | if(l_value < 0) l_value = -1 * l_value; 68 | 69 | int u_min = 3; 70 | int prev_img_luma_index = current_index; 71 | if(imgid != 0) prev_img_luma_index = get_luma_index(imgid-1, nrows, ncols, npix, rowid, colid); 72 | 73 | int prev_img_luma = get_luma(a[prev_img_luma_index], a[prev_img_luma_index + 1], a[prev_img_luma_index + 2]); 74 | int luma_diff = y - prev_img_luma; 75 | if( luma_diff < 0) luma_diff = -1 * luma_diff; 76 | 77 | int u = u_min + luma_diff; 78 | 79 | int v = (u < l_value)? u : l_value; 80 | 81 | /* found that value v */ 82 | if(v < 0) v = -1 * v; 83 | 84 | y = y - 8; 85 | if ( y < 0 ) y = 0; 86 | 87 | r = y + 1.28033 * cr; 88 | g = y - 0.21482 * cb - 0.38059 * cr; 89 | b = y + 2.12798 * cb; 90 | 91 | 92 | _r = (int) r; 93 | _g = (int) g; 94 | _b = (int) b; 95 | 96 | if(_r > 255) _r = 255; 97 | if(_r < 0 ) _r = 0; 98 | 99 | if(_g > 255) _g = 255; 100 | if(_g < 0 ) _g = 0; 101 | 102 | if(_b > 255) _b = 255; 103 | if(_b < 0 ) _b = 0; 104 | 105 | c[current_index] = _r; 106 | c[current_index + 1] = _g; 107 | c[current_index + 2] = _b; 108 | } 109 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/embed_1.cl: -------------------------------------------------------------------------------- 1 | int get_luma_index(int imgid, int nrows, int ncols, int npix, int x, int y) 2 | { 3 | return ((imgid * nrows * ncols * npix) + (x * ncols * npix) + (y * npix)); 4 | } 5 | 6 | int get_luma(int r, int g, int b){ 7 | int luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; 8 | return luma; 9 | } 10 | 11 | __kernel void embed_one(__global const uchar *a, __global uchar *c) 12 | { 13 | // embedding one bit into the image 14 | int imgid = get_global_id(0); 15 | int rowid = get_global_id(1); 16 | int colid = get_global_id(2); 17 | 18 | int nrows = %d; 19 | int ncols = %d; 20 | int npix = %d; 21 | 22 | int current_index = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 23 | 24 | float r, g, b; 25 | int _r, _g, _b; 26 | float y, cb, cr; 27 | r = a[current_index]; 28 | g = a[current_index + 1]; 29 | b = a[current_index + 2]; 30 | y = get_luma(r,g,b); 31 | cb = -0.09991 * r - 0.33609 * g + 0.436 * b; 32 | cr = 0.615 * r - 0.55861 * g -0.05639 * b; 33 | 34 | /* finding that value v */ 35 | int laplacian_sum = 0; 36 | 37 | int xm1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid-1); 38 | int x_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid-1); 39 | int xp1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid-1); 40 | 41 | int xm1_y = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid); 42 | int x_y = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 43 | int xp1_y = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid); 44 | 45 | int xm1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid+1); 46 | int x_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid+1); 47 | int xp1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid+1); 48 | 49 | laplacian_sum += 8 * a[x_y]; 50 | if( colid != 0 ) laplacian_sum -= a[xm1_y]; 51 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_y]; 52 | 53 | if( rowid != 0){ 54 | laplacian_sum -= a[x_ym1]; 55 | if( colid != 0 ) laplacian_sum -= a[xm1_ym1]; 56 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_ym1]; 57 | } 58 | 59 | if( rowid != (nrows - 1)){ 60 | laplacian_sum -= a[x_yp1]; 61 | if( colid != 0 ) laplacian_sum -= a[xm1_yp1]; 62 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_yp1]; 63 | } 64 | 65 | float laplacian_factor = 0.25f * (float)laplacian_sum; 66 | int l_value = (int)(laplacian_factor + 0.5); 67 | if(l_value < 0) l_value = -1 * l_value; 68 | 69 | int u_min = 3; 70 | int prev_img_luma_index = current_index; 71 | if(imgid != 0) prev_img_luma_index = get_luma_index(imgid-1, nrows, ncols, npix, rowid, colid); 72 | 73 | int prev_img_luma = get_luma(a[prev_img_luma_index], a[prev_img_luma_index + 1], a[prev_img_luma_index + 2]); 74 | int luma_diff = y - prev_img_luma; 75 | if( luma_diff < 0) luma_diff = -1 * luma_diff; 76 | 77 | int u = u_min + luma_diff; 78 | 79 | int v = (u < l_value)? u : l_value; 80 | 81 | /* found that value v */ 82 | if(v < 0) v = -1 * v; 83 | 84 | y = y + 8; 85 | if(y > 255) y = 255; 86 | 87 | r = y + 1.28033 * cr; 88 | g = y - 0.21482 * cb - 0.38059 * cr; 89 | b = y + 2.12798 * cb; 90 | 91 | _r = (int) r; 92 | _g = (int) g; 93 | _b = (int) b; 94 | 95 | if(_r > 255) _r = 255; 96 | if(_r < 0 ) _r = 0; 97 | 98 | if(_g > 255) _g = 255; 99 | if(_g < 0 ) _g = 0; 100 | 101 | if(_b > 255) _b = 255; 102 | if(_b < 0 ) _b = 0; 103 | 104 | c[current_index] = _r; 105 | c[current_index + 1] = _g; 106 | c[current_index + 2] = _b; 107 | } 108 | -------------------------------------------------------------------------------- /steganography_ui/modules/embedder/gpu_embedder/embed_0.cl: -------------------------------------------------------------------------------- 1 | int get_luma_index(int imgid, int nrows, int ncols, int npix, int x, int y) 2 | { 3 | return ((imgid * nrows * ncols * npix) + (x * ncols * npix) + (y * npix)); 4 | } 5 | 6 | int get_luma(int r, int g, int b){ 7 | int luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; 8 | return luma; 9 | } 10 | 11 | __kernel void embed_zero(__global const uchar *a, __global uchar *c) 12 | { 13 | // embedding one bit into the image 14 | int imgid = get_global_id(0); 15 | int rowid = get_global_id(1); 16 | int colid = get_global_id(2); 17 | 18 | int nrows = %d; 19 | int ncols = %d; 20 | int npix = %d; 21 | 22 | int current_index = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 23 | 24 | float r, g, b; 25 | int _r, _g, _b; 26 | float y, cb, cr; 27 | r = a[current_index]; 28 | g = a[current_index + 1]; 29 | b = a[current_index + 2]; 30 | y = get_luma(r,g,b); 31 | cb = -0.09991 * r - 0.33609 * g + 0.436 * b; 32 | cr = 0.615 * r - 0.55861 * g -0.05639 * b; 33 | 34 | /* finding that value v */ 35 | int laplacian_sum = 0; 36 | 37 | int xm1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid-1); 38 | int x_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid-1); 39 | int xp1_ym1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid-1); 40 | 41 | int xm1_y = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid); 42 | int x_y = get_luma_index(imgid, nrows, ncols, npix, rowid, colid); 43 | int xp1_y = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid); 44 | 45 | int xm1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid-1, colid+1); 46 | int x_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid, colid+1); 47 | int xp1_yp1 = get_luma_index(imgid, nrows, ncols, npix, rowid+1, colid+1); 48 | 49 | laplacian_sum += 8 * a[x_y]; 50 | if( colid != 0 ) laplacian_sum -= a[xm1_y]; 51 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_y]; 52 | 53 | if( rowid != 0){ 54 | laplacian_sum -= a[x_ym1]; 55 | if( colid != 0 ) laplacian_sum -= a[xm1_ym1]; 56 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_ym1]; 57 | } 58 | 59 | if( rowid != (nrows - 1)){ 60 | laplacian_sum -= a[x_yp1]; 61 | if( colid != 0 ) laplacian_sum -= a[xm1_yp1]; 62 | if( colid != (ncols - 1)) laplacian_sum -= a[xp1_yp1]; 63 | } 64 | 65 | float laplacian_factor = 0.25f * (float)laplacian_sum; 66 | int l_value = (int)(laplacian_factor + 0.5); 67 | if(l_value < 0) l_value = -1 * l_value; 68 | 69 | int u_min = 3; 70 | int prev_img_luma_index = current_index; 71 | if(imgid != 0) prev_img_luma_index = get_luma_index(imgid-1, nrows, ncols, npix, rowid, colid); 72 | 73 | int prev_img_luma = get_luma(a[prev_img_luma_index], a[prev_img_luma_index + 1], a[prev_img_luma_index + 2]); 74 | int luma_diff = y - prev_img_luma; 75 | if( luma_diff < 0) luma_diff = -1 * luma_diff; 76 | 77 | int u = u_min + luma_diff; 78 | 79 | int v = (u < l_value)? u : l_value; 80 | 81 | /* found that value v */ 82 | if(v < 0) v = -1 * v; 83 | 84 | y = y - 8; 85 | if ( y < 0 ) y = 0; 86 | 87 | r = y + 1.28033 * cr; 88 | g = y - 0.21482 * cb - 0.38059 * cr; 89 | b = y + 2.12798 * cb; 90 | 91 | 92 | _r = (int) r; 93 | _g = (int) g; 94 | _b = (int) b; 95 | 96 | if(_r > 255) _r = 255; 97 | if(_r < 0 ) _r = 0; 98 | 99 | if(_g > 255) _g = 255; 100 | if(_g < 0 ) _g = 0; 101 | 102 | if(_b > 255) _b = 255; 103 | if(_b < 0 ) _b = 0; 104 | 105 | c[current_index] = _r; 106 | c[current_index + 1] = _g; 107 | c[current_index + 2] = _b; 108 | } 109 | -------------------------------------------------------------------------------- /steganography_ui/modules/joiner/joiner.py: -------------------------------------------------------------------------------- 1 | # take a bitstring, find the files, join using ffmpeg 2 | import os 3 | import sys 4 | import glob 5 | import json 6 | 7 | 8 | BUCKET_SIZE = -1 9 | NORMAL_SIZE = -1 10 | BITSTRING_SIZE = -1 11 | MIN_ROBUSTNESS_COUNT = -1 12 | 13 | def setup_params(): 14 | global BUCKET_SIZE, NORMAL_SIZE, BITSTRING_SIZE, MIN_ROBUSTNESS_COUNT 15 | fp = open('config.cfg') 16 | data = json.loads(fp.read()) 17 | fp.close() 18 | 19 | BUCKET_SIZE = data['bucket_size'] 20 | NORMAL_SIZE = data['normal_size'] 21 | BITSTRING_SIZE = data['bitstring_size'] 22 | MIN_ROBUSTNESS_COUNT = data['min_robustness_count'] 23 | 24 | 25 | def valid(bitstring): 26 | return ((bitstring.count('1') + bitstring.count('0')) == BITSTRING_SIZE) 27 | 28 | def sufficient_frames(list_normal_files, list_one_files, list_zero_files): 29 | number_embed_frames = BUCKET_SIZE * BITSTRING_SIZE * MIN_ROBUSTNESS_COUNT + (2 * NORMAL_SIZE) 30 | 31 | if len(list_normal_files) < number_embed_frames: return False 32 | if len(list_one_files) < number_embed_frames: return False 33 | if len(list_zero_files) < number_embed_frames: return False 34 | 35 | return True 36 | 37 | def find_robustness_degree(list_normal_files, list_one_files, list_zero_files): 38 | number_embed_frames = min(len(list_normal_files), len(list_one_files), len(list_zero_files)) 39 | number_robust_embed_frames = number_embed_frames - (2 * NORMAL_SIZE) 40 | robustness_degree = number_robust_embed_frames / (BUCKET_SIZE * BITSTRING_SIZE) 41 | return int(robustness_degree) 42 | 43 | def main(): 44 | normal_folder = os.path.join(sys.argv[1], '*.bmp') 45 | one_folder = os.path.join(sys.argv[2], '*.bmp') 46 | zero_folder = os.path.join(sys.argv[3], '*.bmp') 47 | bitstring = sys.argv[4] 48 | 49 | output_folder = sys.argv[5] 50 | 51 | if not valid(bitstring): 52 | print "invalid bitstring" 53 | return 54 | 55 | list_normal_files = glob.glob(normal_folder) 56 | list_one_files = glob.glob(one_folder) 57 | list_zero_files = glob.glob(zero_folder) 58 | 59 | # keep in sorted order 60 | list_normal_files.sort() 61 | list_one_files.sort() 62 | list_zero_files.sort() 63 | 64 | if not sufficient_frames(list_normal_files, list_one_files, list_zero_files): 65 | print "Insufficient frames" 66 | return 67 | 68 | robustness_degree = find_robustness_degree(list_normal_files, list_one_files, list_zero_files) 69 | 70 | frame_number = 1 71 | frame_name = 'img_embed_%08d.bmp' 72 | frame_name = os.path.join(output_folder, frame_name) 73 | cmd_str = 'cp %s '+frame_name 74 | 75 | for i in xrange(NORMAL_SIZE): 76 | print cmd_str % (list_normal_files[frame_number - 1] , frame_number) 77 | frame_number = frame_number + 1 78 | 79 | for robust_count in xrange(robustness_degree): 80 | for i in bitstring: 81 | for ctr in xrange(BUCKET_SIZE): 82 | if i == '1': 83 | print cmd_str % (list_one_files[frame_number - 1], frame_number) 84 | else: 85 | print cmd_str % (list_zero_files[frame_number - 1], frame_number) 86 | 87 | frame_number = frame_number + 1 88 | 89 | for i in xrange(NORMAL_SIZE): 90 | print cmd_str % (list_normal_files[frame_number - 1] , frame_number) 91 | frame_number = frame_number + 1 92 | 93 | remaining_files = list_normal_files[frame_number - 1:] 94 | for i in xrange(len(remaining_files)): 95 | print cmd_str % (remaining_files[i], frame_number) 96 | frame_number = frame_number + 1 97 | 98 | 99 | if __name__ == '__main__': 100 | if len(sys.argv) != 6: 101 | print "wrong usage" 102 | print "Normal folder one folder zero folder bitstring" 103 | else: 104 | setup_params() 105 | main() 106 | -------------------------------------------------------------------------------- /steganography_ui/web/bootstrap_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Video Steganography 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% block extra_scripts %} 26 | {% end %} 27 | 28 | {% block body %} 29 | 30 | 49 | 50 |
    51 |
    52 | 68 | 69 |
    70 |
    71 | {% block dashboard_content %} 72 | {% end %} 73 |
    74 |
    75 |
    76 |
    77 | 78 | {% end %} 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /steganography_ui/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | import tornado.ioloop 4 | import tornado.web 5 | from tornado import template 6 | import json 7 | 8 | # from tornado_handlers import overview_handler, uploads_handler, archive_handler, compare_handler, compare_files_handler, transformation_handler 9 | 10 | from tornado_handlers import * 11 | 12 | 13 | ### Constants BEGIN 14 | __UPLOADS__ = 'uploads/' # custom_utils.py has one too TODO: one copy 15 | IMAGES_PATH = os.path.join(os.getcwd(), "images") 16 | JS_PATH = os.path.join(os.getcwd(), "js") 17 | CSS_PATH = os.path.join(os.getcwd(), "css") 18 | FONTS_PATH = os.path.join(os.getcwd(), "fonts") 19 | VIDEO_PATH = os.path.join(os.getcwd(), "video") 20 | ### Constants END 21 | 22 | class Upload(tornado.web.RequestHandler): 23 | def post(self): 24 | print "GOT request for upload of a file" 25 | fileinfo = self.request.files['myFile'][0] 26 | fname = fileinfo['filename'] 27 | extn = os.path.splitext(fname)[1] 28 | 29 | fh = open(__UPLOADS__ + fname, 'w') 30 | fh.write(fileinfo['body']) 31 | self.finish(json.dumps({'name': fname})) 32 | 33 | class UploadVideo(tornado.web.RequestHandler): 34 | loader = template.Loader('./web') 35 | def post(self): 36 | print "request to upload a video" 37 | fileinfo = self.request.files['myVideo'][0] 38 | fname = fileinfo['filename'] 39 | extn = os.path.splitext(fname)[1] 40 | 41 | fh = open(VIDEO_PATH + "/" + fname, 'w') 42 | fh.write(fileinfo['body']) 43 | 44 | data = self.loader.load('video_upload.html').generate() 45 | self.write(json.dumps({'html': data})) 46 | 47 | class MainHandler(tornado.web.RequestHandler): 48 | loader = template.Loader('./web') 49 | def get(self): 50 | html = self.loader.load('index.html').generate() 51 | self.write(html) 52 | 53 | 54 | def preprocess_stuff(): 55 | print "Creating slides..." 56 | loader = template.Loader('./web') 57 | slide_names = glob.glob('./web/slides/slide_*.html') 58 | slide_names.sort() 59 | fp = open('./web/preprocessed_overview.html', 'w') 60 | str_to_write = '' 61 | if not slide_names: 62 | str_to_write = loader.load('overview.html') 63 | else: 64 | str_to_write = '' 65 | num_slides = len(slide_names) 66 | slides = [] 67 | for i in slide_names: 68 | slide_name = os.path.basename(i) 69 | slides.append(loader.load('slides/%s' % slide_name).generate()) 70 | str_to_write = loader.load('overview_slide.html').generate(num_slides=num_slides, slides=slides) 71 | 72 | fp.write("%s" % str_to_write) 73 | fp.close() 74 | print "done creating slides" 75 | 76 | 77 | preprocess_stuff() 78 | 79 | application = tornado.web.Application([ 80 | (r"/", MainHandler), 81 | (r"/fileupload/", Upload), 82 | (r"/videoupload/", UploadVideo), 83 | (r"/overview/", overview_handler.OverviewHandler), 84 | (r"/uploads/", uploads_handler.UploadsHandler), 85 | (r"/archives/", archive_handler.ArchiveHandler), 86 | (r"/compare/", compare_handler.CompareHandler), 87 | (r"/comparefiles/", compare_files_handler.CompareFilesHandler), 88 | (r"/transform/", transformation_handler.TransformationHandler), 89 | (r"/video_processing/", video_processing_handler.VideoProcessingHandler), 90 | (r"/splitter/", splitter_handler.SplitterHandler), 91 | (r"/embedder/", embedder_handler.EmbedderHandler), 92 | (r"/joiner/", joiner_handler.JoinerHandler), 93 | (r"/detector/", detector_handler.DetectorHandler), 94 | (r"/do-detection/", detector_handler.DoDetection), 95 | (r"/images/(.*)", tornado.web.StaticFileHandler, {'path': IMAGES_PATH}), 96 | (r"/js/(.*)", tornado.web.StaticFileHandler, {'path': JS_PATH}), 97 | (r"/css/(.*)", tornado.web.StaticFileHandler, {"path": CSS_PATH}), 98 | (r"/fonts/(.*)", tornado.web.StaticFileHandler, {"path": FONTS_PATH}), 99 | (r"/video/(.*)", tornado.web.StaticFileHandler, {"path": VIDEO_PATH}), 100 | 101 | 102 | ]) 103 | 104 | if __name__ == '__main__': 105 | application.listen(8888) 106 | tornado.ioloop.IOLoop.instance().start() 107 | -------------------------------------------------------------------------------- /steganography_ui/tornado_handlers/decoder.py: -------------------------------------------------------------------------------- 1 | #take input of two .repr files of luma, output the embedded code in them 2 | import os 3 | import sys 4 | from collections import Counter 5 | 6 | BUCKET_SIZE = -1 7 | BITSTRING_SIZE = -1 8 | NORMAL_SIZE = -1 9 | MIN_ROBUSTNESS_COUNT = -1 10 | 11 | def get_embedded_string_from_bitstring(input_str, ROBUSTNESS_DEGREE): 12 | robustness_arr = [] 13 | for i in xrange(ROBUSTNESS_DEGREE): 14 | bitstring = input_str[i*BITSTRING_SIZE*BUCKET_SIZE:(i+1)*BITSTRING_SIZE*BUCKET_SIZE] 15 | bit_arr = [] 16 | for j in xrange(BITSTRING_SIZE): 17 | bit = bitstring[j*BUCKET_SIZE:(j+1)*BUCKET_SIZE] 18 | if not bit: 19 | print "%dth iteration" % j 20 | print "j * bitstring size = "% (j * BITSTRING_SIZE) 21 | the_bit = max([(v,k) for k,v in Counter(bit).items()])[-1] 22 | bit_arr.append(the_bit) 23 | robustness_arr.append(bit_arr) 24 | 25 | robustness_arr = zip(*robustness_arr) 26 | 27 | final_output = '' 28 | for i in robustness_arr: 29 | the_bit = max([(v,k) for k,v in Counter(i).items()])[-1] 30 | final_output += the_bit 31 | 32 | 33 | return final_output 34 | 35 | def sufficient_frames(list_normal_files, list_recording_files): 36 | number_embed_frames = (2 * NORMAL_SIZE) + BUCKET_SIZE * BITSTRING_SIZE * MIN_ROBUSTNESS_COUNT 37 | print "Number of embed frames required is %d " % number_embed_frames 38 | if len(list_normal_files) > number_embed_frames: return True 39 | if len(list_recording_files) > number_embed_frames: return True 40 | 41 | def find_robustness_degree(list_normal_files, list_recording_files): 42 | number_embed_frames = min(len(list_normal_files), len(list_recording_files)) 43 | number_robust_embed_frames = number_embed_frames - (2 * NORMAL_SIZE) 44 | robustness_degree = number_robust_embed_frames / (BUCKET_SIZE * BITSTRING_SIZE) 45 | return int(robustness_degree) 46 | 47 | def decoder_preprocessing_spidey(a, b): 48 | a = a[75:-75] 49 | 50 | avg_b_74 = float(sum(b[:74]))/len(b[:74]) 51 | for i in xrange(len(b)): 52 | b[i] = b[i] - avg_b_74 53 | 54 | avg_a = float(sum(a))/len(a) 55 | avg_b = float(sum(b))/len(b) 56 | 57 | b = b[74:] 58 | 59 | new_avg_b = float(sum(b))/len(b) 60 | length = len(b) 61 | a = a[:length] 62 | 63 | for i in xrange(length): 64 | a[i] = a[i] - avg_a 65 | b[i] = b[i] - new_avg_b 66 | 67 | return (a, b) 68 | 69 | def main_decoder(params, list_normal_files, list_recording_files): 70 | 71 | global BUCKET_SIZE, MIN_ROBUSTNESS_COUNT, BITSTRING_SIZE, NORMAL_SIZE 72 | BUCKET_SIZE = params['bucket_size'] 73 | MIN_ROBUSTNESS_COUNT = params['min_robustness_count'] 74 | BITSTRING_SIZE = params['bitstring_size'] 75 | NORMAL_SIZE = params['normal_size'] 76 | 77 | if params['name'] == 'spidey': 78 | list_normal_files, list_recording_files = decoder_preprocessing_spidey(list_normal_files, list_recording_files) 79 | # fp_normal = open(sys.argv[1]) 80 | # fp_recording = open(sys.argv[2]) 81 | # list_normal_files = eval(fp_normal.read()) 82 | # list_recording_files = eval(fp_recording.read()) 83 | 84 | if not sufficient_frames(list_normal_files, list_recording_files): 85 | print "Insufficient frames" 86 | return 87 | robustness_degree = find_robustness_degree(list_normal_files, list_recording_files) 88 | 89 | #may need to put a sync between the two lists, but for now assuming that both are perfectly synced and keeping only equal elements 90 | len_frames = min(len(list_normal_files), len(list_recording_files)) 91 | list_normal_files = list_normal_files[:len_frames] 92 | list_recording_files = list_recording_files[:len_frames] 93 | 94 | #trimming the normal frames from both 95 | list_normal_files = list_normal_files[NORMAL_SIZE: len(list_normal_files) - NORMAL_SIZE] 96 | list_recording_files = list_recording_files[NORMAL_SIZE: len(list_recording_files) - NORMAL_SIZE] 97 | 98 | embedded_data = "" 99 | for i,j in zip(list_normal_files, list_recording_files): 100 | if i > j: embedded_data += '0' 101 | elif i < j: embedded_data += '1' 102 | 103 | return get_embedded_string_from_bitstring(embedded_data, robustness_degree - 1) 104 | 105 | -------------------------------------------------------------------------------- /steganography_ui/js/old_handlers.js: -------------------------------------------------------------------------------- 1 | function fileUploadHandler(){ 2 | $('#fileupload'+num_uploads).fileupload({ 3 | dataType: 'json', 4 | add: function(e, data){ 5 | console.log(data.files[0].name); 6 | console.log("added"); 7 | data.context = $('#upload_button'+num_uploads).click(function (){ 8 | data.submit(); 9 | }); 10 | 11 | }, 12 | done: function(e, data){ 13 | data.context.removeClass('glyphicon-upload'); 14 | data.context.addClass('glyphicon-ok'); 15 | $('#fileupload'+num_uploads).replaceWith(data.result.name); 16 | num_uploads = num_uploads + 1; 17 | 18 | $.post("/", {'page': 'uploads', 'num_uploads': num_uploads}, function(data, textstatus, xhrstuff){ 19 | data = JSON.parse(data); 20 | $('#replaceable_content').append(data.html); 21 | fileUploadHandler(); 22 | }); 23 | }, 24 | progressall: function(e, data){ 25 | var progress = parseInt(data.loaded / data.total * 100, 10); 26 | $('.progress-bar').css('width', progress + '%'); 27 | //$($('.progress-bar')[0]).style.width = progress + '%'; 28 | //$('.progress-bar>.sr-only').text(progress+'% Complete'); 29 | }, 30 | }); 31 | }; 32 | 33 | function archiveHandler(){ 34 | $('#archiveTable').on('click','tr', function(){ 35 | if($(this).hasClass('selected_compare')){ 36 | $(this).removeClass('selected_compare'); 37 | $(this).css('background-color', 'white'); 38 | } 39 | else{ 40 | $(this).addClass('selected_compare'); 41 | $(this).css('background-color', '#1DBDB0'); 42 | } 43 | }); 44 | }; 45 | 46 | function onNavClick(){ 47 | var page = this.id; 48 | $('li.active').removeClass('active'); 49 | $(this).parent().addClass('active'); 50 | 51 | 52 | $('#replaceable_content').children().remove(); 53 | 54 | $.post("/", {'page': page, 'num_uploads': num_uploads}, function(data, textstatus, xhrstuff){ 55 | data = JSON.parse(data); 56 | $('#replaceable_content').append(data.html); 57 | console.log("asjasjdda" + data.name); 58 | // call specific function depending on it 59 | if(data.name == 'uploads'){ 60 | fileUploadHandler(); 61 | } 62 | if(data.name == 'archives'){ 63 | archiveHandler(); 64 | } 65 | }); 66 | 67 | }; 68 | 69 | function onOperationSelected(){ 70 | // for compare.html when a particular operation is selected 71 | console.log("calling onOperationSelected for "); 72 | console.log($(this)); 73 | var transformation = $(this).val().trim(); 74 | if(transformation == "Transform") return; 75 | var row = $(this).closest('tr'); 76 | var children = row.children('td'); 77 | var filenames = []; 78 | 79 | for(var i=0; i < children.length; i++){ 80 | var filename = $(children[i]).attr('filename'); 81 | filenames.push(filename); 82 | } 83 | 84 | var to_send = {'filenames': filenames.join(','), 'transformation': transformation, 'num_selects': $('select').length}; 85 | 86 | $.post('/transform', to_send, function(data, textstatus, xhrstuff){ 87 | var data = JSON.parse(data); 88 | $(data.html).insertAfter(row); 89 | var latest_select = $('select').length - 1; 90 | $('#selectpicker'+latest_select).selectpicker(); 91 | $('#selectpicker'+latest_select).on('change', onOperationSelected); 92 | 93 | }); 94 | 95 | } 96 | 97 | function compareFiles(source){ 98 | var files_to_compare = ""; 99 | if(source == "archive_page"){ 100 | var rows_selected = $('.selected_compare'); 101 | var file_compare_str = []; 102 | for(var i=0; i < rows_selected.length; i++){ 103 | file_compare_str[i] = $($(rows_selected[i]).children()[0]).text(); 104 | } 105 | 106 | files_to_compare = file_compare_str.join(','); 107 | } 108 | else{ 109 | // in compare.html 110 | files_to_compare = $('#files_to_compare').val() 111 | } 112 | var data = {'page': 'compare', 'compare': files_to_compare, 'num_selects': $('select').length}; 113 | 114 | $.post('/', data, function(data, textstatus, xhrstuff){ 115 | var data = JSON.parse(data); 116 | $('#replaceable_content').children().remove(); 117 | $('#replaceable_content').append(data.html); 118 | 119 | $('.sidebar_navigation>.active').removeClass('active'); 120 | $('#compare').addClass('active'); 121 | 122 | var latest_select = $('select').length - 1; 123 | $('#selectpicker'+latest_select).selectpicker(); 124 | $('#selectpicker'+latest_select).on('change', onOperationSelected); 125 | }); 126 | }; 127 | 128 | 129 | function onLoad(){ 130 | num_uploads=0; 131 | console.log("loaded"); 132 | $('.sidebar_navigation#nav_overview').on('click', onNavOverview); 133 | $('.sidebar_navigation#nav_uploads').on('click', onNavUploads); 134 | $('.sidebar_navigation#nav_archives').on('click', onNavArchives); 135 | $('.sidebar_navigation#nav_compare').on('click', onNavCompare); 136 | }; 137 | -------------------------------------------------------------------------------- /steganography_ui/css/bootstrap-select.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * bootstrap-select v1.5.3 3 | * http://silviomoreto.github.io/bootstrap-select/ 4 | * 5 | * Copyright 2013 bootstrap-select 6 | * Licensed under the MIT license 7 | */.bootstrap-select.btn-group:not(.input-group-btn),.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:0}.bootstrap-select.btn-group.pull-right,.bootstrap-select.btn-group[class*="span"].pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"].pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn){width:220px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%;padding-right:25px}.error .bootstrap-select .btn{border:1px solid #b94a48}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{display:inline-block;overflow:hidden;width:100%;float:left;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;z-index:2000;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{position:absolute;display:inline-block;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small,.bootstrap-select.btn-group .dropdown-menu li.active:not(.disabled)>a small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #fff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.bootstrap-select.btn-group .no-results{padding:3px;background:#f5f5f5;margin:0 5px}.bootstrap-select.btn-group .dropdown-menu .notify{position:absolute;bottom:5px;width:96%;margin:0 2%;min-height:26px;padding:3px 5px;background:#f5f5f5;border:1px solid #e3e3e3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox,.bootstrap-select .bs-actionsbox{padding:4px 8px}.bootstrap-select .bs-actionsbox{float:left;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select-searchbox+.bs-actionsbox{padding:0 8px 4px}.bootstrap-select-searchbox input{margin-bottom:0}.bootstrap-select .bs-actionsbox .btn-group button{width:50%} -------------------------------------------------------------------------------- /steganography_ui/css/bootstrap-select.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * bootstrap-select v1.5.3 3 | * http://silviomoreto.github.io/bootstrap-select/ 4 | * 5 | * Copyright 2013 bootstrap-select 6 | * Licensed under the MIT license 7 | */ 8 | 9 | .bootstrap-select.btn-group:not(.input-group-btn), 10 | .bootstrap-select.btn-group[class*="span"] { 11 | float: none; 12 | display: inline-block; 13 | margin-bottom: 10px; 14 | margin-left: 0; 15 | } 16 | .form-search .bootstrap-select.btn-group, 17 | .form-inline .bootstrap-select.btn-group, 18 | .form-horizontal .bootstrap-select.btn-group { 19 | margin-bottom: 0; 20 | } 21 | 22 | .bootstrap-select.form-control { 23 | margin-bottom: 0; 24 | padding: 0; 25 | border: none; 26 | } 27 | 28 | .bootstrap-select.btn-group.pull-right, 29 | .bootstrap-select.btn-group[class*="span"].pull-right, 30 | .row-fluid .bootstrap-select.btn-group[class*="span"].pull-right { 31 | float: right; 32 | } 33 | 34 | .input-append .bootstrap-select.btn-group { 35 | margin-left: -1px; 36 | } 37 | 38 | .input-prepend .bootstrap-select.btn-group { 39 | margin-right: -1px; 40 | } 41 | 42 | .bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) { 43 | width: 220px; 44 | } 45 | 46 | .bootstrap-select { 47 | /*width: 220px\9; IE8 and below*/ 48 | width: 220px\0; /*IE9 and below*/ 49 | } 50 | 51 | .bootstrap-select.form-control:not([class*="span"]) { 52 | width: 100%; 53 | } 54 | 55 | .bootstrap-select > .btn { 56 | width: 100%; 57 | padding-right: 25px; 58 | } 59 | 60 | .error .bootstrap-select .btn { 61 | border: 1px solid #b94a48; 62 | } 63 | 64 | .bootstrap-select.show-menu-arrow.open > .btn { 65 | z-index: 2051; 66 | } 67 | 68 | .bootstrap-select .btn:focus { 69 | outline: thin dotted #333333 !important; 70 | outline: 5px auto -webkit-focus-ring-color !important; 71 | outline-offset: -2px; 72 | } 73 | 74 | .bootstrap-select.btn-group .btn .filter-option { 75 | display: inline-block; 76 | overflow: hidden; 77 | width: 100%; 78 | float: left; 79 | text-align: left; 80 | } 81 | 82 | .bootstrap-select.btn-group .btn .caret { 83 | position: absolute; 84 | top: 50%; 85 | right: 12px; 86 | margin-top: -2px; 87 | vertical-align: middle; 88 | } 89 | 90 | .bootstrap-select.btn-group > .disabled, 91 | .bootstrap-select.btn-group .dropdown-menu li.disabled > a { 92 | cursor: not-allowed; 93 | } 94 | 95 | .bootstrap-select.btn-group > .disabled:focus { 96 | outline: none !important; 97 | } 98 | 99 | .bootstrap-select.btn-group[class*="span"] .btn { 100 | width: 100%; 101 | } 102 | 103 | .bootstrap-select.btn-group .dropdown-menu { 104 | min-width: 100%; 105 | z-index: 2000; 106 | -webkit-box-sizing: border-box; 107 | -moz-box-sizing: border-box; 108 | box-sizing: border-box; 109 | } 110 | 111 | .bootstrap-select.btn-group .dropdown-menu.inner { 112 | position: static; 113 | border: 0; 114 | padding: 0; 115 | margin: 0; 116 | -webkit-border-radius: 0; 117 | -moz-border-radius: 0; 118 | border-radius: 0; 119 | -webkit-box-shadow: none; 120 | -moz-box-shadow: none; 121 | box-shadow: none; 122 | } 123 | 124 | .bootstrap-select.btn-group .dropdown-menu dt { 125 | display: block; 126 | padding: 3px 20px; 127 | cursor: default; 128 | } 129 | 130 | .bootstrap-select.btn-group .div-contain { 131 | overflow: hidden; 132 | } 133 | 134 | .bootstrap-select.btn-group .dropdown-menu li { 135 | position: relative; 136 | } 137 | 138 | .bootstrap-select.btn-group .dropdown-menu li > a.opt { 139 | position: relative; 140 | padding-left: 35px; 141 | } 142 | 143 | .bootstrap-select.btn-group .dropdown-menu li > a { 144 | cursor: pointer; 145 | } 146 | 147 | .bootstrap-select.btn-group .dropdown-menu li > dt small { 148 | font-weight: normal; 149 | } 150 | 151 | .bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark { 152 | position: absolute; 153 | display: inline-block; 154 | right: 15px; 155 | margin-top: 2.5px; 156 | } 157 | 158 | .bootstrap-select.btn-group .dropdown-menu li a i.check-mark { 159 | display: none; 160 | } 161 | 162 | .bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text { 163 | margin-right: 34px; 164 | } 165 | 166 | .bootstrap-select.btn-group .dropdown-menu li small { 167 | padding-left: 0.5em; 168 | } 169 | 170 | .bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:hover small, 171 | .bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:focus small, 172 | .bootstrap-select.btn-group .dropdown-menu li.active:not(.disabled) > a small { 173 | color: #64b1d8; 174 | color: rgba(255,255,255,0.4); 175 | } 176 | 177 | .bootstrap-select.btn-group .dropdown-menu li > dt small { 178 | font-weight: normal; 179 | } 180 | 181 | .bootstrap-select.show-menu-arrow .dropdown-toggle:before { 182 | content: ''; 183 | display: inline-block; 184 | border-left: 7px solid transparent; 185 | border-right: 7px solid transparent; 186 | border-bottom: 7px solid #CCC; 187 | border-bottom-color: rgba(0, 0, 0, 0.2); 188 | position: absolute; 189 | bottom: -4px; 190 | left: 9px; 191 | display: none; 192 | } 193 | 194 | .bootstrap-select.show-menu-arrow .dropdown-toggle:after { 195 | content: ''; 196 | display: inline-block; 197 | border-left: 6px solid transparent; 198 | border-right: 6px solid transparent; 199 | border-bottom: 6px solid white; 200 | position: absolute; 201 | bottom: -4px; 202 | left: 10px; 203 | display: none; 204 | } 205 | 206 | .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before { 207 | bottom: auto; 208 | top: -3px; 209 | border-top: 7px solid #ccc; 210 | border-bottom: 0; 211 | border-top-color: rgba(0, 0, 0, 0.2); 212 | } 213 | 214 | .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after { 215 | bottom: auto; 216 | top: -3px; 217 | border-top: 6px solid #ffffff; 218 | border-bottom: 0; 219 | } 220 | 221 | .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before { 222 | right: 12px; 223 | left: auto; 224 | } 225 | .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after { 226 | right: 13px; 227 | left: auto; 228 | } 229 | 230 | .bootstrap-select.show-menu-arrow.open > .dropdown-toggle:before, 231 | .bootstrap-select.show-menu-arrow.open > .dropdown-toggle:after { 232 | display: block; 233 | } 234 | 235 | .bootstrap-select.btn-group .no-results { 236 | padding: 3px; 237 | background: #f5f5f5; 238 | margin: 0 5px; 239 | } 240 | 241 | .bootstrap-select.btn-group .dropdown-menu .notify { 242 | position: absolute; 243 | bottom: 5px; 244 | width: 96%; 245 | margin: 0 2%; 246 | min-height: 26px; 247 | padding: 3px 5px; 248 | background: #f5f5f5; 249 | border: 1px solid #e3e3e3; 250 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.05); 251 | pointer-events: none; 252 | opacity: 0.9; 253 | -webkit-box-sizing: border-box; 254 | -moz-box-sizing: border-box; 255 | box-sizing: border-box; 256 | } 257 | 258 | .mobile-device { 259 | position: absolute; 260 | top: 0; 261 | left: 0; 262 | display: block !important; 263 | width: 100%; 264 | height: 100% !important; 265 | opacity: 0; 266 | } 267 | 268 | .bootstrap-select.fit-width { 269 | width: auto !important; 270 | } 271 | 272 | .bootstrap-select.btn-group.fit-width .btn .filter-option { 273 | position: static; 274 | } 275 | 276 | .bootstrap-select.btn-group.fit-width .btn .caret { 277 | position: static; 278 | top: auto; 279 | margin-top: -1px; 280 | } 281 | 282 | .control-group.error .bootstrap-select .dropdown-toggle{ 283 | border-color: #b94a48; 284 | } 285 | 286 | .bootstrap-select-searchbox, 287 | .bootstrap-select .bs-actionsbox { 288 | padding: 4px 8px; 289 | } 290 | 291 | .bootstrap-select .bs-actionsbox { 292 | float: left; 293 | width: 100%; 294 | -webkit-box-sizing: border-box; 295 | -moz-box-sizing: border-box; 296 | box-sizing: border-box; 297 | } 298 | 299 | .bootstrap-select-searchbox + .bs-actionsbox { 300 | padding: 0 8px 4px; 301 | } 302 | 303 | .bootstrap-select-searchbox input { 304 | margin-bottom: 0; 305 | } 306 | 307 | .bootstrap-select .bs-actionsbox .btn-group button { 308 | width: 50%; 309 | } -------------------------------------------------------------------------------- /steganography_ui/js/my_handlers.js: -------------------------------------------------------------------------------- 1 | function fileUploadHandler(){ 2 | $('#fileupload'+num_uploads).fileupload({ 3 | dataType: 'json', 4 | add: function(e, data){ 5 | console.log(data.files[0].name); 6 | console.log("added"); 7 | data.context = $('#upload_button'+num_uploads).click(function (){ 8 | data.submit(); 9 | }); 10 | 11 | }, 12 | done: function(e, data){ 13 | data.context.removeClass('glyphicon-upload'); 14 | data.context.addClass('glyphicon-ok'); 15 | $('#fileupload'+num_uploads).replaceWith(data.result.name); 16 | num_uploads = num_uploads + 1; 17 | 18 | $.post("/uploads/", {'num_uploads': num_uploads}, function(data, textstatus, xhrstuff){ 19 | data = JSON.parse(data); 20 | $('#replaceable_content').append(data.html); 21 | fileUploadHandler(); 22 | }); 23 | }, 24 | progressall: function(e, data){ 25 | var progress = parseInt(data.loaded / data.total * 100, 10); 26 | $('.progress-bar').css('width', progress + '%'); 27 | }, 28 | replaceFileInput: false, 29 | }); 30 | }; 31 | 32 | 33 | function onNavOverview(){ 34 | console.log("navigated to Overview"); 35 | $.post('/overview/', {}, function(data, textstatus, xhrstuff){ 36 | console.log(data); 37 | data = JSON.parse(data); 38 | $('#replaceable_content').children().remove(); 39 | $('#replaceable_content').append(data.html); 40 | 41 | $('.carousel').carousel({ 42 | interval: false 43 | }); 44 | 45 | var last_slide_num = localStorage.getItem('current_slide'); 46 | if (last_slide_num == null) last_slide_num = 0; 47 | else last_slide_num = parseInt(last_slide_num); 48 | 49 | console.log('last slide num was ' + last_slide_num); 50 | $('.carousel').carousel(last_slide_num); 51 | 52 | $('#overview_carousel_id').on('slide.bs.carousel', function () { 53 | 54 | var slide_num = $('.item.active').attr('id'); 55 | slide_num = parseInt(slide_num.split('stegoSlide')[1]) 56 | slide_num = slide_num + 1; 57 | localStorage.setItem('current_slide', slide_num); 58 | console.log("changed slide_num to " + slide_num); 59 | }) 60 | }); 61 | } 62 | 63 | function onNavUploads(){ 64 | console.log("navigated to uploads"); 65 | 66 | $.post('/uploads/', {'num_uploads': num_uploads}, function(data, textstatus, xhrstuff){ 67 | data = JSON.parse(data); 68 | $('#replaceable_content').children().remove(); 69 | $('#replaceable_content').append(data.html); 70 | 71 | fileUploadHandler(); 72 | }); 73 | } 74 | 75 | 76 | function onOperationSelected(){ 77 | // for compare.html when a particular operation is selected 78 | 79 | var transformation = $(this).val().trim(); 80 | if(transformation == "Transform") return; 81 | var row = $(this).closest('tr'); 82 | var children = row.children('td'); 83 | var filenames = []; 84 | 85 | var docs = []; 86 | 87 | for(var i=0; i < children.length - 1; i++){ 88 | var filename = $(children[i]).attr('filename'); 89 | var compatiable = $(children[i]).attr('compatiable'); 90 | if(compatiable == "True") compatiable = true; 91 | else compatiable = false; 92 | 93 | docs.push({'name':filename, 'compatiable': compatiable}); 94 | } 95 | 96 | var to_send = {'documents': JSON.stringify(docs), 'transformation': transformation, 'num_selects': $('select').length}; 97 | 98 | $.post('/transform/', to_send, function(data, textstatus, xhrstuff){ 99 | var data = JSON.parse(data); 100 | $(data.html).insertAfter(row); 101 | var latest_select = $('select').length - 1; 102 | $('#selectpicker'+latest_select).selectpicker(); 103 | $('#selectpicker'+latest_select).on('change', onOperationSelected); 104 | 105 | }); 106 | 107 | } 108 | 109 | 110 | 111 | function compareFiles(files_to_compare){ 112 | console.log("Compareing files" + files_to_compare); 113 | 114 | files_to_compare = files_to_compare.trim(); 115 | if(files_to_compare == '') return; 116 | 117 | data = {'files': files_to_compare, 'num_selects': $('select').length}; 118 | 119 | $.post('/comparefiles/', data, function(data, textstatus, xhrstuff){ 120 | var data = JSON.parse(data); 121 | console.log(data); 122 | 123 | $('#replaceable_content').children().remove(); 124 | $('#replaceable_content').append(data.html); 125 | 126 | $('.sidebar_navigation>.active').removeClass('active'); 127 | $('#compare').addClass('active'); 128 | 129 | var latest_select = $('select').length - 1; 130 | $('#selectpicker' + latest_select).selectpicker(); 131 | $('#selectpicker' + latest_select).on('change', onOperationSelected); 132 | }); 133 | } 134 | 135 | function onNavArchives(){ 136 | console.log("navigated to archives"); 137 | 138 | $.post('/archives/', {}, function(data, textstatus, xhrstuff){ 139 | data = JSON.parse(data); 140 | $('#replaceable_content').children().remove(); 141 | $('#replaceable_content').append(data.html); 142 | 143 | $('#archiveTable').on('click', 'tr', function(){ 144 | if($(this).hasClass('selected_compare')){ 145 | $(this).removeClass('selected_compare'); 146 | $(this).css('background-color', 'white'); 147 | } 148 | else{ 149 | $(this).addClass('selected_compare'); 150 | $(this).css('background-color', '#1DBDB0'); 151 | } 152 | }); 153 | 154 | $('#archiveCompareBtn').on('click', function(){ 155 | console.log("Clicked"); 156 | 157 | var files_to_compare = ""; 158 | var rows_selected = $('.selected_compare'); 159 | var file_compare_str = []; 160 | 161 | for(var i=0; i < rows_selected.length; i++) 162 | file_compare_str[i] = $($(rows_selected[i]).children()[0]).text(); 163 | 164 | files_to_compare = file_compare_str.join(','); 165 | 166 | compareFiles(files_to_compare); 167 | }); 168 | 169 | }); 170 | 171 | } 172 | function onNavCompare(){ 173 | console.log("navigated to compare"); 174 | $.post('/compare/', {}, function(data, textstatus, xhrstuff){ 175 | data = JSON.parse(data); 176 | $('#replaceable_content').children().remove(); 177 | $('#replaceable_content').append(data.html); 178 | 179 | $('#compareBtn').on('click', function(){ 180 | $('#modalArchiveList').modal('show'); 181 | 182 | $('#compareModalTable').on('click', 'tr', function(){ 183 | if($(this).hasClass('selected_compare')){ 184 | $(this).removeClass('selected_compare'); 185 | $(this).css('background-color', 'white'); 186 | } 187 | else{ 188 | $(this).addClass('selected_compare'); 189 | $(this).css('background-color', '#1DBDB0'); 190 | } 191 | }); 192 | 193 | }); 194 | }); 195 | 196 | } 197 | 198 | function onModalFileCompare(){ 199 | 200 | var files_to_compare = ""; 201 | var rows_selected = $('.selected_compare'); 202 | var file_compare_str = []; 203 | 204 | for(var i=0; i < rows_selected.length; i++) 205 | file_compare_str[i] = $($(rows_selected[i]).children()[0]).text(); 206 | 207 | files_to_compare = file_compare_str.join(','); 208 | console.log(files_to_compare); 209 | 210 | //$('#modalArchiveList').modal('hide'); 211 | 212 | compareFiles(files_to_compare); 213 | }; 214 | 215 | function onNavJoiner(){ 216 | 217 | console.log("navigated to joiner"); 218 | $.post('/joiner/', {}, function(data, textstatus, xhrstuff){ 219 | data = JSON.parse(data); 220 | $('#replaceable_content').children().remove(); 221 | $('#replaceable_content').append(data.html); 222 | }); 223 | }; 224 | 225 | function onNavSplitter(){ 226 | console.log("navigated to splitter"); 227 | $.post('/splitter/', {}, function(data, textstatus, xhrstuff){ 228 | data = JSON.parse(data); 229 | $('#replaceable_content').children().remove(); 230 | $('#replaceable_content').append(data.html); 231 | }); 232 | }; 233 | 234 | function onNavEmbedder(){ 235 | console.log("navigated to embedder"); 236 | $.post('/embedder/', {}, function(data, textstatus, xhrstuff){ 237 | data = JSON.parse(data); 238 | $('#replaceable_content').children().remove(); 239 | $('#replaceable_content').append(data.html); 240 | 241 | }); 242 | 243 | }; 244 | 245 | function onNavDetector(){ 246 | console.log("navigated to detector"); 247 | $.post('/detector/', {}, function(data, textstatus, xhrstuff){ 248 | data = JSON.parse(data); 249 | $('#replaceable_content').children().remove(); 250 | $('#replaceable_content').append(data.html); 251 | 252 | }); 253 | 254 | }; 255 | 256 | 257 | function onLoad(){ 258 | num_uploads=0; 259 | localStorage.setItem('current_slide', 0); 260 | console.log("loaded"); 261 | $('.sidebar_navigation#nav_overview').on('click', onNavOverview); 262 | $('.sidebar_navigation#nav_uploads').on('click', onNavUploads); 263 | $('.sidebar_navigation#nav_archives').on('click', onNavArchives); 264 | $('.sidebar_navigation#nav_compare').on('click', onNavCompare); 265 | 266 | $('.sidebar_navigation#nav_video_processing').on('click', onNavVideoProcessing); 267 | $('.sidebar_navigation#nav_joiner').on('click', onNavJoiner); 268 | $('.sidebar_navigation#nav_splitter').on('click', onNavSplitter); 269 | $('.sidebar_navigation#nav_embedder').on('click', onNavEmbedder); 270 | $('.sidebar_navigation#nav_detector').on('click', onNavDetector); 271 | }; 272 | -------------------------------------------------------------------------------- /steganography_ui/js/jquery.iframe-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Iframe Transport Plugin 1.8.2 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * http://www.opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, window, document */ 13 | 14 | (function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['jquery'], factory); 19 | } else { 20 | // Browser globals: 21 | factory(window.jQuery); 22 | } 23 | }(function ($) { 24 | 'use strict'; 25 | 26 | // Helper variable to create unique names for the transport iframes: 27 | var counter = 0; 28 | 29 | // The iframe transport accepts four additional options: 30 | // options.fileInput: a jQuery collection of file input fields 31 | // options.paramName: the parameter name for the file form data, 32 | // overrides the name property of the file input field(s), 33 | // can be a string or an array of strings. 34 | // options.formData: an array of objects with name and value properties, 35 | // equivalent to the return data of .serializeArray(), e.g.: 36 | // [{name: 'a', value: 1}, {name: 'b', value: 2}] 37 | // options.initialIframeSrc: the URL of the initial iframe src, 38 | // by default set to "javascript:false;" 39 | $.ajaxTransport('iframe', function (options) { 40 | if (options.async) { 41 | // javascript:false as initial iframe src 42 | // prevents warning popups on HTTPS in IE6: 43 | /*jshint scripturl: true */ 44 | var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', 45 | /*jshint scripturl: false */ 46 | form, 47 | iframe, 48 | addParamChar; 49 | return { 50 | send: function (_, completeCallback) { 51 | form = $('
    '); 52 | form.attr('accept-charset', options.formAcceptCharset); 53 | addParamChar = /\?/.test(options.url) ? '&' : '?'; 54 | // XDomainRequest only supports GET and POST: 55 | if (options.type === 'DELETE') { 56 | options.url = options.url + addParamChar + '_method=DELETE'; 57 | options.type = 'POST'; 58 | } else if (options.type === 'PUT') { 59 | options.url = options.url + addParamChar + '_method=PUT'; 60 | options.type = 'POST'; 61 | } else if (options.type === 'PATCH') { 62 | options.url = options.url + addParamChar + '_method=PATCH'; 63 | options.type = 'POST'; 64 | } 65 | // IE versions below IE8 cannot set the name property of 66 | // elements that have already been added to the DOM, 67 | // so we set the name along with the iframe HTML markup: 68 | counter += 1; 69 | iframe = $( 70 | '' 72 | ).bind('load', function () { 73 | var fileInputClones, 74 | paramNames = $.isArray(options.paramName) ? 75 | options.paramName : [options.paramName]; 76 | iframe 77 | .unbind('load') 78 | .bind('load', function () { 79 | var response; 80 | // Wrap in a try/catch block to catch exceptions thrown 81 | // when trying to access cross-domain iframe contents: 82 | try { 83 | response = iframe.contents(); 84 | // Google Chrome and Firefox do not throw an 85 | // exception when calling iframe.contents() on 86 | // cross-domain requests, so we unify the response: 87 | if (!response.length || !response[0].firstChild) { 88 | throw new Error(); 89 | } 90 | } catch (e) { 91 | response = undefined; 92 | } 93 | // The complete callback returns the 94 | // iframe content document as response object: 95 | completeCallback( 96 | 200, 97 | 'success', 98 | {'iframe': response} 99 | ); 100 | // Fix for IE endless progress bar activity bug 101 | // (happens on form submits to iframe targets): 102 | $('') 103 | .appendTo(form); 104 | window.setTimeout(function () { 105 | // Removing the form in a setTimeout call 106 | // allows Chrome's developer tools to display 107 | // the response result 108 | form.remove(); 109 | }, 0); 110 | }); 111 | form 112 | .prop('target', iframe.prop('name')) 113 | .prop('action', options.url) 114 | .prop('method', options.type); 115 | if (options.formData) { 116 | $.each(options.formData, function (index, field) { 117 | $('') 118 | .prop('name', field.name) 119 | .val(field.value) 120 | .appendTo(form); 121 | }); 122 | } 123 | if (options.fileInput && options.fileInput.length && 124 | options.type === 'POST') { 125 | fileInputClones = options.fileInput.clone(); 126 | // Insert a clone for each file input field: 127 | options.fileInput.after(function (index) { 128 | return fileInputClones[index]; 129 | }); 130 | if (options.paramName) { 131 | options.fileInput.each(function (index) { 132 | $(this).prop( 133 | 'name', 134 | paramNames[index] || options.paramName 135 | ); 136 | }); 137 | } 138 | // Appending the file input fields to the hidden form 139 | // removes them from their original location: 140 | form 141 | .append(options.fileInput) 142 | .prop('enctype', 'multipart/form-data') 143 | // enctype must be set as encoding for IE: 144 | .prop('encoding', 'multipart/form-data'); 145 | // Remove the HTML5 form attribute from the input(s): 146 | options.fileInput.removeAttr('form'); 147 | } 148 | form.submit(); 149 | // Insert the file input fields at their original location 150 | // by replacing the clones with the originals: 151 | if (fileInputClones && fileInputClones.length) { 152 | options.fileInput.each(function (index, input) { 153 | var clone = $(fileInputClones[index]); 154 | // Restore the original name and form properties: 155 | $(input) 156 | .prop('name', clone.prop('name')) 157 | .attr('form', clone.attr('form')); 158 | clone.replaceWith(input); 159 | }); 160 | } 161 | }); 162 | form.append(iframe).appendTo(document.body); 163 | }, 164 | abort: function () { 165 | if (iframe) { 166 | // javascript:false as iframe src aborts the request 167 | // and prevents warning popups on HTTPS in IE6. 168 | // concat is used to avoid the "Script URL" JSLint error: 169 | iframe 170 | .unbind('load') 171 | .prop('src', initialIframeSrc); 172 | } 173 | if (form) { 174 | form.remove(); 175 | } 176 | } 177 | }; 178 | } 179 | }); 180 | 181 | // The iframe transport returns the iframe content document as response. 182 | // The following adds converters from iframe to text, json, html, xml 183 | // and script. 184 | // Please note that the Content-Type for JSON responses has to be text/plain 185 | // or text/html, if the browser doesn't include application/json in the 186 | // Accept header, else IE will show a download dialog. 187 | // The Content-Type for XML responses on the other hand has to be always 188 | // application/xml or text/xml, so IE properly parses the XML response. 189 | // See also 190 | // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation 191 | $.ajaxSetup({ 192 | converters: { 193 | 'iframe text': function (iframe) { 194 | return iframe && $(iframe[0].body).text(); 195 | }, 196 | 'iframe json': function (iframe) { 197 | return iframe && $.parseJSON($(iframe[0].body).text()); 198 | }, 199 | 'iframe html': function (iframe) { 200 | return iframe && $(iframe[0].body).html(); 201 | }, 202 | 'iframe xml': function (iframe) { 203 | var xmlDoc = iframe && iframe[0]; 204 | return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : 205 | $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || 206 | $(xmlDoc.body).html()); 207 | }, 208 | 'iframe script': function (iframe) { 209 | return iframe && $.globalEval($(iframe[0].body).text()); 210 | } 211 | } 212 | }); 213 | 214 | })); 215 | -------------------------------------------------------------------------------- /steganography_ui/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.1 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /steganography_ui/js/docs.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | Holder - 2.3.1 - client side image placeholders 4 | (c) 2012-2014 Ivan Malopinsky / http://imsky.co 5 | 6 | Provided under the MIT License. 7 | Commercial use requires attribution. 8 | 9 | */ 10 | var Holder=Holder||{};!function(a,b){function c(a,b,c){b=parseInt(b,10),a=parseInt(a,10);var d=Math.max(b,a),e=Math.min(b,a),f=1/12,g=Math.min(.75*e,.75*d*f);return{height:Math.round(Math.max(c.size,g))}}function d(a){var b=[];for(p in a)a.hasOwnProperty(p)&&b.push(p+":"+a[p]);return b.join(";")}function e(a){var b=a.ctx,d=a.dimensions,e=a.template,f=a.ratio,g=a.holder,h="literal"==g.textmode,i="exact"==g.textmode,j=c(d.width,d.height,e),k=j.height,l=d.width*f,m=d.height*f,n=e.font?e.font:"Arial,Helvetica,sans-serif";canvas.width=l,canvas.height=m,b.textAlign="center",b.textBaseline="middle",b.fillStyle=e.background,b.fillRect(0,0,l,m),b.fillStyle=e.foreground,b.font="bold "+k+"px "+n;var o=e.text?e.text:Math.floor(d.width)+"x"+Math.floor(d.height);if(h){var d=g.dimensions;o=d.width+"x"+d.height}else if(i&&g.exact_dimensions){var d=g.exact_dimensions;o=Math.floor(d.width)+"x"+Math.floor(d.height)}var p=b.measureText(o).width;return p/l>=.75&&(k=Math.floor(.75*k*(l/p))),b.font="bold "+k*f+"px "+n,b.fillText(o,l/2,m/2,l),canvas.toDataURL("image/png")}function f(a){var b=a.dimensions,d=a.template,e=a.holder,f="literal"==e.textmode,g="exact"==e.textmode,h=c(b.width,b.height,d),i=h.height,j=b.width,k=b.height,l=d.font?d.font:"Arial,Helvetica,sans-serif",m=d.text?d.text:Math.floor(b.width)+"x"+Math.floor(b.height);if(f){var b=e.dimensions;m=b.width+"x"+b.height}else if(g&&e.exact_dimensions){var b=e.exact_dimensions;m=Math.floor(b.width)+"x"+Math.floor(b.height)}var n=z({text:m,width:j,height:k,text_height:i,font:l,template:d});return"data:image/svg+xml;base64,"+btoa(n)}function g(a){return r.use_canvas&&!r.use_svg?e(a):f(a)}function h(a,b,c,d){var e=c.dimensions,f=c.theme,h=c.text?decodeURIComponent(c.text):c.text,i=e.width+"x"+e.height;f=h?o(f,{text:h}):f,f=c.font?o(f,{font:c.font}):f,b.setAttribute("data-src",d),c.theme=f,b.holder_data=c,"image"==a?(b.setAttribute("alt",h?h:f.text?f.text+" ["+i+"]":i),(r.use_fallback||!c.auto)&&(b.style.width=e.width+"px",b.style.height=e.height+"px"),r.use_fallback?b.style.backgroundColor=f.background:(b.setAttribute("src",g({ctx:w,dimensions:e,template:f,ratio:x,holder:c})),c.textmode&&"exact"==c.textmode&&(v.push(b),k(b)))):"background"==a?r.use_fallback||(b.style.backgroundImage="url("+g({ctx:w,dimensions:e,template:f,ratio:x,holder:c})+")",b.style.backgroundSize=e.width+"px "+e.height+"px"):"fluid"==a&&(b.setAttribute("alt",h?h:f.text?f.text+" ["+i+"]":i),"%"==e.height.slice(-1)?b.style.height=e.height:null!=c.auto&&c.auto||(b.style.height=e.height+"px"),"%"==e.width.slice(-1)?b.style.width=e.width:null!=c.auto&&c.auto||(b.style.width=e.width+"px"),("inline"==b.style.display||""===b.style.display||"none"==b.style.display)&&(b.style.display="block"),j(b),r.use_fallback?b.style.backgroundColor=f.background:(v.push(b),k(b)))}function i(a,b){var c={height:a.clientHeight,width:a.clientWidth};return c.height||c.width?(a.removeAttribute("data-holder-invisible"),c):(a.setAttribute("data-holder-invisible",!0),void b.call(this,a))}function j(b){if(b.holder_data){var c=i(b,a.invisible_error_fn(j));if(c){var d=b.holder_data;d.initial_dimensions=c,d.fluid_data={fluid_height:"%"==d.dimensions.height.slice(-1),fluid_width:"%"==d.dimensions.width.slice(-1),mode:null},d.fluid_data.fluid_width&&!d.fluid_data.fluid_height?(d.fluid_data.mode="width",d.fluid_data.ratio=d.initial_dimensions.width/parseFloat(d.dimensions.height)):!d.fluid_data.fluid_width&&d.fluid_data.fluid_height&&(d.fluid_data.mode="height",d.fluid_data.ratio=parseFloat(d.dimensions.width)/d.initial_dimensions.height)}}}function k(b){var c;c=null==b.nodeType?v:[b];for(var d in c)if(c.hasOwnProperty(d)){var e=c[d];if(e.holder_data){var f=e.holder_data,h=i(e,a.invisible_error_fn(k));if(h){if(f.fluid){if(f.auto)switch(f.fluid_data.mode){case"width":h.height=h.width/f.fluid_data.ratio;break;case"height":h.width=h.height*f.fluid_data.ratio}e.setAttribute("src",g({ctx:w,dimensions:h,template:f.theme,ratio:x,holder:f}))}f.textmode&&"exact"==f.textmode&&(f.exact_dimensions=h,e.setAttribute("src",g({ctx:w,dimensions:f.dimensions,template:f.theme,ratio:x,holder:f})))}}}}function l(b,c){for(var d={theme:o(y.themes.gray,{})},e=!1,f=b.length,g=0;f>g;g++){var h=b[g];a.flags.dimensions.match(h)?(e=!0,d.dimensions=a.flags.dimensions.output(h)):a.flags.fluid.match(h)?(e=!0,d.dimensions=a.flags.fluid.output(h),d.fluid=!0):a.flags.textmode.match(h)?d.textmode=a.flags.textmode.output(h):a.flags.colors.match(h)?d.theme=a.flags.colors.output(h):c.themes[h]?c.themes.hasOwnProperty(h)&&(d.theme=o(c.themes[h],{})):a.flags.font.match(h)?d.font=a.flags.font.output(h):a.flags.auto.match(h)?d.auto=!0:a.flags.text.match(h)&&(d.text=a.flags.text.output(h))}return e?d:!1}function m(a,b){var c="complete",d="readystatechange",e=!1,f=e,g=!0,h=a.document,i=h.documentElement,j=h.addEventListener?"addEventListener":"attachEvent",k=h.addEventListener?"removeEventListener":"detachEvent",l=h.addEventListener?"":"on",m=function(g){(g.type!=d||h.readyState==c)&&(("load"==g.type?a:h)[k](l+g.type,m,e),!f&&(f=!0)&&b.call(a,null))},n=function(){try{i.doScroll("left")}catch(a){return void setTimeout(n,50)}m("poll")};if(h.readyState==c)b.call(a,"lazy");else{if(h.createEventObject&&i.doScroll){try{g=!a.frameElement}catch(o){}g&&n()}h[j](l+"DOMContentLoaded",m,e),h[j](l+d,m,e),a[j](l+"load",m,e)}}function n(a,b){var a=a.match(/^(\W)?(.*)/),b=b||document,c=b["getElement"+(a[1]?"#"==a[1]?"ById":"sByClassName":"sByTagName")],d=c.call(b,a[2]),e=[];return null!==d&&(e=d.length||0===d.length?d:[d]),e}function o(a,b){var c={};for(var d in a)a.hasOwnProperty(d)&&(c[d]=a[d]);for(var d in b)b.hasOwnProperty(d)&&(c[d]=b[d]);return c}var q={use_svg:!1,use_canvas:!1,use_fallback:!1},r={},s=!1;canvas=document.createElement("canvas");var t=1,u=1,v=[];if(canvas.getContext)if(canvas.toDataURL("image/png").indexOf("data:image/png")<0)q.use_fallback=!0;else var w=canvas.getContext("2d");else q.use_fallback=!0;document.createElementNS&&document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect&&(q.use_svg=!0,q.use_canvas=!1),q.use_fallback||(t=window.devicePixelRatio||1,u=w.webkitBackingStorePixelRatio||w.mozBackingStorePixelRatio||w.msBackingStorePixelRatio||w.oBackingStorePixelRatio||w.backingStorePixelRatio||1);var x=t/u,y={domain:"holder.js",images:"img",bgnodes:".holderjs",themes:{gray:{background:"#eee",foreground:"#aaa",size:12},social:{background:"#3a5a97",foreground:"#fff",size:12},industrial:{background:"#434A52",foreground:"#C2F200",size:12},sky:{background:"#0D8FDB",foreground:"#fff",size:12},vine:{background:"#39DBAC",foreground:"#1E292C",size:12},lava:{background:"#F8591A",foreground:"#1C2846",size:12}},stylesheet:""};a.flags={dimensions:{regex:/^(\d+)x(\d+)$/,output:function(a){var b=this.regex.exec(a);return{width:+b[1],height:+b[2]}}},fluid:{regex:/^([0-9%]+)x([0-9%]+)$/,output:function(a){var b=this.regex.exec(a);return{width:b[1],height:b[2]}}},colors:{regex:/#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i,output:function(a){var b=this.regex.exec(a);return{size:y.themes.gray.size,foreground:"#"+b[2],background:"#"+b[1]}}},text:{regex:/text\:(.*)/,output:function(a){return this.regex.exec(a)[1]}},font:{regex:/font\:(.*)/,output:function(a){return this.regex.exec(a)[1]}},auto:{regex:/^auto$/},textmode:{regex:/textmode\:(.*)/,output:function(a){return this.regex.exec(a)[1]}}};var z=function(){if(window.XMLSerializer){var a=new XMLSerializer,b="http://www.w3.org/2000/svg",c=document.createElementNS(b,"svg");c.webkitMatchesSelector&&c.setAttribute("xmlns","http://www.w3.org/2000/svg");var e=document.createElementNS(b,"rect"),f=document.createElementNS(b,"text"),g=document.createTextNode(null);return f.setAttribute("text-anchor","middle"),f.appendChild(g),c.appendChild(e),c.appendChild(f),function(b){return c.setAttribute("width",b.width),c.setAttribute("height",b.height),e.setAttribute("width",b.width),e.setAttribute("height",b.height),e.setAttribute("fill",b.template.background),f.setAttribute("x",b.width/2),f.setAttribute("y",b.height/2),g.nodeValue=b.text,f.setAttribute("style",d({fill:b.template.foreground,"font-weight":"bold","font-size":b.text_height+"px","font-family":b.font,"dominant-baseline":"central"})),a.serializeToString(c)}}}();for(var A in a.flags)a.flags.hasOwnProperty(A)&&(a.flags[A].match=function(a){return a.match(this.regex)});a.invisible_error_fn=function(){return function(a){if(a.hasAttribute("data-holder-invisible"))throw new Error("Holder: invisible placeholder")}},a.add_theme=function(b,c){return null!=b&&null!=c&&(y.themes[b]=c),a},a.add_image=function(b,c){var d=n(c);if(d.length)for(var e=0,f=d.length;f>e;e++){var g=document.createElement("img");g.setAttribute("data-src",b),d[e].appendChild(g)}return a},a.run=function(b){r=o({},q),s=!0;var c=o(y,b),d=[],e=[],f=[];for(null!=c.use_canvas&&c.use_canvas&&(r.use_canvas=!0,r.use_svg=!1),"string"==typeof c.images?e=n(c.images):window.NodeList&&c.images instanceof window.NodeList?e=c.images:window.Node&&c.images instanceof window.Node?e=[c.images]:window.HTMLCollection&&c.images instanceof window.HTMLCollection&&(e=c.images),"string"==typeof c.bgnodes?f=n(c.bgnodes):window.NodeList&&c.elements instanceof window.NodeList?f=c.bgnodes:window.Node&&c.bgnodes instanceof window.Node&&(f=[c.bgnodes]),k=0,j=e.length;j>k;k++)d.push(e[k]);var g=document.getElementById("holderjs-style");g||(g=document.createElement("style"),g.setAttribute("id","holderjs-style"),g.type="text/css",document.getElementsByTagName("head")[0].appendChild(g)),c.nocss||(g.styleSheet?g.styleSheet.cssText+=c.stylesheet:g.appendChild(document.createTextNode(c.stylesheet)));for(var i=new RegExp(c.domain+'/(.*?)"?\\)'),j=f.length,k=0;j>k;k++){var m=window.getComputedStyle(f[k],null).getPropertyValue("background-image"),p=m.match(i),t=f[k].getAttribute("data-background-src");if(p){var u=l(p[1].split("/"),c);u&&h("background",f[k],u,m)}else if(null!=t){var u=l(t.substr(t.lastIndexOf(c.domain)+c.domain.length+1).split("/"),c);u&&h("background",f[k],u,m)}}for(j=d.length,k=0;j>k;k++){var v,w;w=v=m=null;try{w=d[k].getAttribute("src"),attr_datasrc=d[k].getAttribute("data-src")}catch(x){}if(null==attr_datasrc&&w&&w.indexOf(c.domain)>=0?m=w:attr_datasrc&&attr_datasrc.indexOf(c.domain)>=0&&(m=attr_datasrc),m){var u=l(m.substr(m.lastIndexOf(c.domain)+c.domain.length+1).split("/"),c);u&&(u.fluid?h("fluid",d[k],u,m):h("image",d[k],u,m))}}return a},m(b,function(){window.addEventListener?(window.addEventListener("resize",k,!1),window.addEventListener("orientationchange",k,!1)):window.attachEvent("onresize",k),s||a.run({})}),"function"==typeof define&&define.amd&&define([],function(){return a}),function(){function a(a){this.message=a}var b="undefined"!=typeof exports?exports:this,c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a.prototype=Error(),a.prototype.name="InvalidCharacterError",b.btoa||(b.btoa=function(b){for(var d,e,f=0,g=c,h="";b.charAt(0|f)||(g="=",f%1);h+=g.charAt(63&d>>8-8*(f%1))){if(e=b.charCodeAt(f+=.75),e>255)throw new a("'btoa' failed");d=d<<8|e}return h}),b.atob||(b.atob=function(b){if(b=b.replace(/=+$/,""),1==b.length%4)throw new a("'atob' failed");for(var d,e,f=0,g=0,h="";e=b.charAt(g++);~e&&(d=f%4?64*d+e:e,f++%4)?h+=String.fromCharCode(255&d>>(6&-2*f)):0)e=c.indexOf(e);return h})}(),document.getElementsByClassName||(document.getElementsByClassName=function(a){var b,c,d,e=document,f=[];if(e.querySelectorAll)return e.querySelectorAll("."+a);if(e.evaluate)for(c=".//*[contains(concat(' ', @class, ' '), ' "+a+" ')]",b=e.evaluate(c,e,null,0,null);d=b.iterateNext();)f.push(d);else for(b=e.getElementsByTagName("*"),c=new RegExp("(^|\\s)"+a+"(\\s|$)"),d=0;d li > a:hover, 152 | .dropdown-menu > li > a:focus { 153 | background-color: #e8e8e8; 154 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 155 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 156 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 157 | background-repeat: repeat-x; 158 | } 159 | .dropdown-menu > .active > a, 160 | .dropdown-menu > .active > a:hover, 161 | .dropdown-menu > .active > a:focus { 162 | background-color: #357ebd; 163 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 164 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 165 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 166 | background-repeat: repeat-x; 167 | } 168 | .navbar-default { 169 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 170 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 171 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 172 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 173 | background-repeat: repeat-x; 174 | border-radius: 4px; 175 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 176 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 177 | } 178 | .navbar-default .navbar-nav > .active > a { 179 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 180 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 181 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 182 | background-repeat: repeat-x; 183 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 184 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 185 | } 186 | .navbar-brand, 187 | .navbar-nav > li > a { 188 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 189 | } 190 | .navbar-inverse { 191 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 192 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 193 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 194 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 195 | background-repeat: repeat-x; 196 | } 197 | .navbar-inverse .navbar-nav > .active > a { 198 | background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%); 199 | background-image: linear-gradient(to bottom, #222 0%, #282828 100%); 200 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 201 | background-repeat: repeat-x; 202 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 203 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 204 | } 205 | .navbar-inverse .navbar-brand, 206 | .navbar-inverse .navbar-nav > li > a { 207 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 208 | } 209 | .navbar-static-top, 210 | .navbar-fixed-top, 211 | .navbar-fixed-bottom { 212 | border-radius: 0; 213 | } 214 | .alert { 215 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 216 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 217 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 218 | } 219 | .alert-success { 220 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 221 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 222 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 223 | background-repeat: repeat-x; 224 | border-color: #b2dba1; 225 | } 226 | .alert-info { 227 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 228 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 229 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 230 | background-repeat: repeat-x; 231 | border-color: #9acfea; 232 | } 233 | .alert-warning { 234 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 235 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 236 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 237 | background-repeat: repeat-x; 238 | border-color: #f5e79e; 239 | } 240 | .alert-danger { 241 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 242 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 243 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 244 | background-repeat: repeat-x; 245 | border-color: #dca7a7; 246 | } 247 | .progress { 248 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 249 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 250 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 251 | background-repeat: repeat-x; 252 | } 253 | .progress-bar { 254 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 255 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 256 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 257 | background-repeat: repeat-x; 258 | } 259 | .progress-bar-success { 260 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 261 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 262 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 263 | background-repeat: repeat-x; 264 | } 265 | .progress-bar-info { 266 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 267 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 268 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 269 | background-repeat: repeat-x; 270 | } 271 | .progress-bar-warning { 272 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 273 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 274 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 275 | background-repeat: repeat-x; 276 | } 277 | .progress-bar-danger { 278 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 279 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 280 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 281 | background-repeat: repeat-x; 282 | } 283 | .list-group { 284 | border-radius: 4px; 285 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 286 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 287 | } 288 | .list-group-item.active, 289 | .list-group-item.active:hover, 290 | .list-group-item.active:focus { 291 | text-shadow: 0 -1px 0 #3071a9; 292 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 293 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 294 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 295 | background-repeat: repeat-x; 296 | border-color: #3278b3; 297 | } 298 | .panel { 299 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 300 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 301 | } 302 | .panel-default > .panel-heading { 303 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 304 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 305 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 306 | background-repeat: repeat-x; 307 | } 308 | .panel-primary > .panel-heading { 309 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 310 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 311 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 312 | background-repeat: repeat-x; 313 | } 314 | .panel-success > .panel-heading { 315 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 316 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 317 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 318 | background-repeat: repeat-x; 319 | } 320 | .panel-info > .panel-heading { 321 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 322 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 323 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 324 | background-repeat: repeat-x; 325 | } 326 | .panel-warning > .panel-heading { 327 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 328 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 329 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 330 | background-repeat: repeat-x; 331 | } 332 | .panel-danger > .panel-heading { 333 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 334 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .well { 339 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 340 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 341 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 342 | background-repeat: repeat-x; 343 | border-color: #dcdcdc; 344 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 345 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 346 | } 347 | /*# sourceMappingURL=bootstrap-theme.css.map */ 348 | --------------------------------------------------------------------------------