diff --git a/actions/generate.php b/actions/generate.php
new file mode 100644
index 0000000..2d6fed2
--- /dev/null
+++ b/actions/generate.php
@@ -0,0 +1,56 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+$sw = input('service_worker');
+
+if($sw == 'enabled') {
+ //copied from original sw
+ $siteurl = ossn_site_url();
+ if(substr($siteurl, 0, 8) != 'https://') {
+ ossn_trigger_message(ossn_print('favicon:generator:sw:https:error'), 'error');
+ redirect(REF);
+ }
+}
+$logo = new OssnFile();
+$logo->setFile('logo');
+$logo->setExtension(array(
+ 'jpg',
+ 'png',
+ 'jpeg',
+ 'jfif',
+ 'gif',
+ 'webp',
+));
+if(isset($logo->file['tmp_name']) && $logo->typeAllowed()) {
+ $file = $logo->file['tmp_name'];
+
+ $info = getimagesize($file);
+ $width = $info[0];
+ $height = $info[1];
+
+ if($width != $height) {
+ ossn_trigger_message(ossn_print('favicon:generator:logo:dim:error'), 'error');
+ redirect(REF);
+ }
+
+ $time = time();
+
+ $icon = new Favicon\Generator($file, $time);
+ if($sw == 'enabled') {
+ $icon->serviceworker = true;
+ }
+ $icon->generate();
+
+ ossn_trigger_message(ossn_print('favicon:generator:logo:done'));
+ redirect(REF);
+} else {
+ ossn_trigger_message(ossn_print('favicon:generator:logo:error'), 'error');
+ redirect(REF);
+}
\ No newline at end of file
diff --git a/actions/reset.php b/actions/reset.php
new file mode 100644
index 0000000..e9cbbb6
--- /dev/null
+++ b/actions/reset.php
@@ -0,0 +1,13 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+ $path = ossn_route()->www . 'sfavicons/';
+ \OssnFile::DeleteDir($path);
+ redirect(REF);
\ No newline at end of file
diff --git a/classes/Generator.php b/classes/Generator.php
new file mode 100644
index 0000000..7c3439f
--- /dev/null
+++ b/classes/Generator.php
@@ -0,0 +1,188 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+namespace Favicon;
+class Generator {
+ public function __construct($file, $time) {
+ $this->file = $file;
+ $this->time = $time;
+ $this->serviceworker = false;
+ }
+ public function browserXML() {
+ $file = __FaviconGenerator__ . 'configs/browserconfig.xml.dist';
+ $file = file_get_contents($file);
+
+ $urllogo_310 = ossn_site_url("sfavicons/favicon-310x310.png?v{$this->time}");
+ $urllogo_512 = ossn_site_url("sfavicons/favicon-512x512.png?v{$this->time}");
+
+ $newfile = str_replace('{512logo_url}', $urllogo_512, $file);
+ $newfile = str_replace('{310logo_url}', $urllogo_310, $newfile);
+ return $newfile;
+ }
+ public function webManifest() {
+ $urllogo_192 = ossn_site_url("sfavicons/favicon-192x192.png?v{$this->time}");
+ $urllogo_512 = ossn_site_url("sfavicons/favicon-512x512.png?v{$this->time}");
+
+ $sitename = ossn_site_settings('site_name');
+
+ $manifest = array(
+ 'name' => $sitename,
+ 'short_name' => $sitename,
+ 'icons' => array(
+ array(
+ 'src' => $urllogo_192,
+ 'sizes' => '192x192',
+ 'type' => 'image/png',
+ 'purpose' => 'any maskable',
+ ),
+ array(
+ 'src' => $urllogo_512,
+ 'sizes' => '512x512',
+ 'type' => 'image/png',
+ 'purpose' => 'any maskable',
+ ),
+ ),
+
+ 'theme_color' => '#ffffff',
+ 'background_color' => '#ffffff',
+ 'start_url' => ossn_site_url(),
+ 'display' => 'standalone',
+ 'orientation' => 'any',
+ 'scope' => ossn_site_url(),
+ );
+ if(isset($this->serviceworker) && $this->serviceworker === true) {
+ $manifest['serviceworker'] = array(
+ 'src' => ossn_site_url('sfavicons/sw.js'),
+ );
+ }
+ return json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+ }
+ public function html() {
+ return ossn_plugin_view('favicon_generator/html', array(
+ 'time' => $this->time,
+ ));
+ }
+ public function yandex() {
+ $manifest = array(
+ 'version' => '1.0',
+ 'api_version' => 1,
+ 'layout' => array(
+ 'logo' => ossn_site_url("sfavicons/favicon-50x50.png?v{$this->time}"),
+ 'color' => 'background_color',
+ 'show_title' => true,
+ ),
+ );
+ return json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+ }
+ public function ico($png32, $destination) {
+ if(!is_file($png32) || !is_dir($destination)) {
+ return false;
+ }
+ require_once __FaviconGenerator__ . 'vendors/png2ico/php2ico.php';
+ $icon = new \php2ico($png32);
+ return $icon->save_ico($destination . 'favicon.ico');
+ }
+ public function resize($input_name, $maxwidth, $maxheight) {
+ // Get the size information from the image
+ $imgsizearray = getimagesize($input_name);
+ if($imgsizearray == false) {
+ return false;
+ }
+ $image = new \OssnImage($input_name);
+
+ $accepted_formats = array(
+ 'image/jpeg' => 'jpeg',
+ 'image/pjpeg' => 'jpeg',
+ 'image/png' => 'png',
+ 'image/x-png' => 'png',
+ 'image/webp' => 'webp',
+ );
+
+ // make sure the function is available
+ $load_function = 'imagecreatefrom' . $accepted_formats[$imgsizearray['mime']];
+ if(!is_callable($load_function)) {
+ return false;
+ }
+ $image->resizeToBestFit($maxwidth, $maxheight);
+ return $image->getImageAsString(IMAGETYPE_PNG, 50);
+ }
+ public function generate() {
+ if(!is_file($this->file)) {
+ return false;
+ }
+ $path = ossn_route()->www . 'sfavicons/';
+
+ //delete old dir and create again
+ \OssnFile::DeleteDir($path);
+ mkdir($path, 0755, true);
+
+ //png icon files
+ $config = array(
+ 16,
+ 32,
+ 37,
+ 48,
+ 50,
+ 57,
+ 60,
+ 72,
+ 76,
+ 96,
+ 114,
+ 120,
+ 144,
+ 152,
+ 180,
+ 192,
+ 150,
+ 310,
+ 512,
+ );
+ foreach ($config as $size) {
+ $new = $this->resize($this->file, $size, $size, false);
+ file_put_contents($path . "favicon-{$size}x{$size}.png", $new);
+ }
+
+ //ico file
+ //we need to use 32px PNG file
+ if(!$this->ico($path . 'favicon-32x32.png', $path)) {
+ //failed for some reason
+ //delete generated icons
+ error_log("FaviconGenerator: Failed to generate ICO file from {$path}");
+ \OssnFile::DeleteDir($path);
+ return false;
+ }
+
+ //webmanifest
+ $manifest = $this->webManifest();
+ file_put_contents($path . 'manifest.json', $manifest);
+
+ //yandex
+ $yandex = $this->yandex();
+ file_put_contents($path . 'yandex-browser-manifest.json', $yandex);
+
+ //browserxml
+ $browserxml = $this->browserXML();
+ file_put_contents($path . 'browserconfig.xml', $browserxml);
+
+ //header
+ $html = $this->html();
+ file_put_contents($path . 'head.html', $html);
+
+ //service worker
+ if(isset($this->serviceworker) && $this->serviceworker === true) {
+ $sw = ossn_plugin_view('favicon_generator/favicon-sw');
+ file_put_contents($path . 'sw.js', $sw);
+ }
+
+ //generated settings
+ file_put_contents($path . 'generated', 1);
+ }
+}
\ No newline at end of file
diff --git a/configs/browserconfig.xml.dist b/configs/browserconfig.xml.dist
new file mode 100644
index 0000000..3df87b2
--- /dev/null
+++ b/configs/browserconfig.xml.dist
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ #2b5797
+
+
+
diff --git a/locale/ossn.en.php b/locale/ossn.en.php
new file mode 100644
index 0000000..643122a
--- /dev/null
+++ b/locale/ossn.en.php
@@ -0,0 +1,25 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+ossn_register_languages('en', array(
+ 'favicons:generator:select' => 'Select',
+ 'favicons:generator:enabled' => 'Enabled',
+ 'favicons:generator:disabled' => 'Disabled',
+ 'favicon:generator:sw:https:error' => 'Enabling PWA / service Worker not possible - Your site must be HTTPS supported.',
+ 'favicon:generator:logo:dim:error' => 'Logo must be square and at least 512px * 512px',
+ 'favicon:generator:logo:info' => 'Logo File (at least 512px * 512px and square)',
+ 'favicon:generator:logo:info:2' => 'Make sure logo file is no more than 1MB',
+ 'favicon:generator:sw' => 'Enable Service Worker',
+ 'favicon:generator:sw:info' => 'When Enabled it will enable progressive web app (PWA). Allowing users to install PWA on supported device. Make sure you are using SSL protocol (https).',
+ 'favicon:generator:logo:error' => 'Invalid Logo file',
+ 'favicon:generator:logo:done' => 'Logo has been generated',
+ 'favicon:generator:reset' => 'Reset Now',
+ 'favicon:generator:reset:info' => 'Icons are already generated. You can reset to change the favicon for you website.',
+));
\ No newline at end of file
diff --git a/ossn_com.php b/ossn_com.php
new file mode 100644
index 0000000..b51d6ce
--- /dev/null
+++ b/ossn_com.php
@@ -0,0 +1,52 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+
+define('__FaviconGenerator__', ossn_route()->com . 'FaviconGenerator/');
+ossn_register_class(array(
+ 'Favicon\Generator' => __FaviconGenerator__ . 'classes/Generator.php',
+));
+ossn_register_callback('ossn', 'init', function () {
+ if(ossn_isAdminLoggedin()) {
+ ossn_register_com_panel('FaviconGenerator', 'settings');
+ ossn_register_action('favicon_generator/settings', __FaviconGenerator__ . 'actions/generate.php');
+ ossn_register_action('favicon_generator/reset', __FaviconGenerator__ . 'actions/reset.php');
+ }
+ //taken from original favicons component
+ ossn_add_hook('page', 'override:view', '_com_favicons_page_handler');
+ ossn_extend_view('ossn/admin/head', '_com_favicons_add_head_tags');
+
+ //from original service worker
+ ossn_extend_view('ossn/site/head', '_com_serviceworker_enable_service_worker');
+ ossn_extend_view('ossn/admin/head', '_com_serviceworker_enable_service_worker');
+});
+function _com_serviceworker_enable_service_worker() {
+ $sw_file = ossn_route()->www . 'sfavicons/sw.js';
+ $sw_url = ossn_site_url() . 'sfavicons/sw.js';
+ if(file_exists($sw_file)) {
+ $script =
+ "\n\n";
+ return $script;
+ }
+}
+function _com_favicons_page_handler($hook, $type, $return, $params) {
+ if($params['handler'] != 'shared_content') {
+ ossn_extend_view('ossn/site/head', '_com_favicons_add_head_tags');
+ }
+}
+
+function _com_favicons_add_head_tags() {
+ $tags_file = ossn_route()->www . 'sfavicons/head.html';
+ if(file_exists($tags_file)) {
+ $content = file_get_contents($tags_file, true);
+ $tags = "\n" . $content . "\n";
+ return $tags;
+ }
+}
\ No newline at end of file
diff --git a/ossn_com.xml b/ossn_com.xml
new file mode 100644
index 0000000..012ae28
--- /dev/null
+++ b/ossn_com.xml
@@ -0,0 +1,20 @@
+
+
+ Favicon Generator
+ FaviconGenerator
+ Core Team
+ Favicon Generator
+ Open Source Social Network License (OSSN LICENSE) v4.0
+ https://www.opensource-socialnetwork.org.com/
+ http://www.opensource-socialnetwork.org/licence
+ 1.0
+
+ ossn_version
+ 7.6
+
+
+ ossn_component
+ Favicons
+ disabled
+
+
diff --git a/plugins/default/favicon_generator/favicon-sw-unregister.php b/plugins/default/favicon_generator/favicon-sw-unregister.php
new file mode 100644
index 0000000..2a76c6b
--- /dev/null
+++ b/plugins/default/favicon_generator/favicon-sw-unregister.php
@@ -0,0 +1,13 @@
+self.addEventListener('install', function(e) {
+ self.skipWaiting();
+});
+
+self.addEventListener('activate', function(e) {
+ self.registration.unregister()
+ .then(function() {
+ return self.clients.matchAll();
+ })
+ .then(function(clients) {
+ clients.forEach(client => client.navigate(client.url))
+ });
+});
\ No newline at end of file
diff --git a/plugins/default/favicon_generator/favicon-sw.php b/plugins/default/favicon_generator/favicon-sw.php
new file mode 100644
index 0000000..7779d54
--- /dev/null
+++ b/plugins/default/favicon_generator/favicon-sw.php
@@ -0,0 +1,47 @@
+self.addEventListener('install', function(e) {
+ e.waitUntil(
+ caches.open('ossn').then(function(cache) {
+ return cache.addAll([
+ // array of cacheable pages ...
+ ]);
+ })
+ );
+});
+
+self.addEventListener('fetch', function(e) {
+ if(e.request.url.includes('edit?section=siteappinstaller')) {
+ e.respondWith(
+ caches.match(e.request).then(function(response) {
+ return response || fetch(e.request);
+ })
+ );
+ }
+});
+
+self.addEventListener('push', event => {
+ if (!(self.Notification && self.Notification.permission === 'granted')) {
+ return;
+ }
+ try {
+ var notification = JSON.parse(event.data.text());
+ var title = notification.title;
+ var icon = notification.icon;
+ var body = notification.body;
+ } catch (e) {
+ var title = 'Developer Test Push';
+ var icon = '';
+ var body = event.data.text();
+ }
+ event.waitUntil(
+ self.registration.showNotification(title, {
+ body: body,
+ icon: icon,
+ // vibrate: [100, 50, 100],
+ // data: { ourKey: 1 },
+ requireInteraction: true,
+ // actions: [
+ // {action: 'go', title: 'go to site'},
+ // ]
+ })
+ );
+});
diff --git a/plugins/default/favicon_generator/html.php b/plugins/default/favicon_generator/html.php
new file mode 100644
index 0000000..e238c86
--- /dev/null
+++ b/plugins/default/favicon_generator/html.php
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/default/forms/favicon_generator/admin.php b/plugins/default/forms/favicon_generator/admin.php
new file mode 100644
index 0000000..eb7ef5f
--- /dev/null
+++ b/plugins/default/forms/favicon_generator/admin.php
@@ -0,0 +1,59 @@
+www . 'sfavicons/';
+ if(!file_exists($path . 'generated')){
+?>
+
+
+
+
+ 'service_worker',
+ 'placeholder' => ossn_print('favicons:generator:select'),
+ 'options' => array(
+ 'enabled' => ossn_print('favicons:generator:enabled'),
+ 'disabled' => ossn_print('favicons:generator:disabled'),
+ ),
+ ));
+ ?>
+
+
+
+
+
+
+
+
+ {$item}" ;
+ }
+?>
+
+
+
\ No newline at end of file
diff --git a/plugins/default/settings/administrator/FaviconGenerator/settings.php b/plugins/default/settings/administrator/FaviconGenerator/settings.php
new file mode 100644
index 0000000..205edf2
--- /dev/null
+++ b/plugins/default/settings/administrator/FaviconGenerator/settings.php
@@ -0,0 +1,14 @@
+
+ * @copyright (C) Engr. Arsalan Shah
+ * @license Open Source Social Network License (OSSN LICENSE) http://www.opensource-socialnetwork.org/licence
+ * @link https://www.opensource-socialnetwork.org/
+ */
+echo ossn_view_form('favicon_generator/admin', array(
+ 'action' => ossn_site_url() . 'action/favicon_generator/settings',
+ 'class' => 'favicon-generator-form-admin',
+));
\ No newline at end of file
diff --git a/vendors/png2ico/php2ico.php b/vendors/png2ico/php2ico.php
new file mode 100644
index 0000000..bf9809c
--- /dev/null
+++ b/vendors/png2ico/php2ico.php
@@ -0,0 +1,263 @@
+_has_requirements = true;
+
+
+ if ( false != $file )
+ $this->add_image( $file, $sizes );
+ }
+
+ /**
+ * Add an image to the generator.
+ *
+ * This function adds a source image to the generator. It serves two main purposes: add a source image if one was
+ * not supplied to the constructor and to add additional source images so that different images can be supplied for
+ * different sized images in the resulting ICO file. For instance, a small source image can be used for the small
+ * resolutions while a larger source image can be used for large resolutions.
+ *
+ * @param string $file Path to the source image file.
+ * @param array $sizes Optional. An array of sizes (each size is an array with a width and height) that the source image should be rendered at in the generated ICO file. If sizes are not supplied, the size of the source image will be used.
+ * @return boolean true on success and false on failure.
+ */
+ function add_image( $file, $sizes = array() ) {
+ if ( ! $this->_has_requirements )
+ return false;
+
+ if ( false === ( $im = $this->_load_image_file( $file ) ) )
+ return false;
+
+
+ if ( empty( $sizes ) )
+ $sizes = array( imagesx( $im ), imagesy( $im ) );
+
+ // If just a single size was passed, put it in array.
+ if ( ! is_array( $sizes[0] ) )
+ $sizes = array( $sizes );
+
+ foreach ( (array) $sizes as $size ) {
+ list( $width, $height ) = $size;
+
+ $new_im = imagecreatetruecolor( $width, $height );
+
+ imagecolortransparent( $new_im, imagecolorallocatealpha( $new_im, 0, 0, 0, 127 ) );
+ imagealphablending( $new_im, false );
+ imagesavealpha( $new_im, true );
+
+ $source_width = imagesx( $im );
+ $source_height = imagesy( $im );
+
+ if ( false === imagecopyresampled( $new_im, $im, 0, 0, 0, 0, $width, $height, $source_width, $source_height ) )
+ continue;
+
+ $this->_add_image_data( $new_im );
+ }
+
+ return true;
+ }
+
+ /**
+ * Write the ICO file data to a file path.
+ *
+ * @param string $file Path to save the ICO file data into.
+ * @return boolean true on success and false on failure.
+ */
+ function save_ico( $file ) {
+ if ( ! $this->_has_requirements )
+ return false;
+
+ if ( false === ( $data = $this->_get_ico_data() ) )
+ return false;
+
+ if ( false === ( $fh = fopen( $file, 'w' ) ) )
+ return false;
+
+ if ( false === ( fwrite( $fh, $data ) ) ) {
+ fclose( $fh );
+ return false;
+ }
+
+ fclose( $fh );
+
+ return true;
+ }
+
+ /**
+ * Generate the final ICO data by creating a file header and adding the image data.
+ *
+ * @access private
+ */
+ function _get_ico_data() {
+ if ( ! is_array( $this->_images ) || empty( $this->_images ) )
+ return false;
+
+
+ $data = pack( 'vvv', 0, 1, count( $this->_images ) );
+ $pixel_data = '';
+
+ $icon_dir_entry_size = 16;
+
+ $offset = 6 + ( $icon_dir_entry_size * count( $this->_images ) );
+
+ foreach ( $this->_images as $image ) {
+ $data .= pack( 'CCCCvvVV', $image['width'], $image['height'], $image['color_palette_colors'], 0, 1, $image['bits_per_pixel'], $image['size'], $offset );
+ $pixel_data .= $image['data'];
+
+ $offset += $image['size'];
+ }
+
+ $data .= $pixel_data;
+ unset( $pixel_data );
+
+
+ return $data;
+ }
+
+ /**
+ * Take a GD image resource and change it into a raw BMP format.
+ *
+ * @access private
+ */
+ function _add_image_data( $im ) {
+ $width = imagesx( $im );
+ $height = imagesy( $im );
+
+
+ $pixel_data = array();
+
+ $opacity_data = array();
+ $current_opacity_val = 0;
+
+ for ( $y = $height - 1; $y >= 0; $y-- ) {
+ for ( $x = 0; $x < $width; $x++ ) {
+ $color = imagecolorat( $im, $x, $y );
+
+ $alpha = ( $color & 0x7F000000 ) >> 24;
+ $alpha = ( 1 - ( $alpha / 127 ) ) * 255;
+
+ $color &= 0xFFFFFF;
+ $color |= 0xFF000000 & ( $alpha << 24 );
+
+ $pixel_data[] = $color;
+
+
+ $opacity = ( $alpha <= 127 ) ? 1 : 0;
+
+ $current_opacity_val = ( $current_opacity_val << 1 ) | $opacity;
+
+ if ( ( ( $x + 1 ) % 32 ) == 0 ) {
+ $opacity_data[] = $current_opacity_val;
+ $current_opacity_val = 0;
+ }
+ }
+
+ if ( ( $x % 32 ) > 0 ) {
+ while ( ( $x++ % 32 ) > 0 )
+ $current_opacity_val = $current_opacity_val << 1;
+
+ $opacity_data[] = $current_opacity_val;
+ $current_opacity_val = 0;
+ }
+ }
+
+ $image_header_size = 40;
+ $color_mask_size = $width * $height * 4;
+ $opacity_mask_size = ( ceil( $width / 32 ) * 4 ) * $height;
+
+
+ $data = pack( 'VVVvvVVVVVV', 40, $width, ( $height * 2 ), 1, 32, 0, 0, 0, 0, 0, 0 );
+
+ foreach ( $pixel_data as $color )
+ $data .= pack( 'V', $color );
+
+ foreach ( $opacity_data as $opacity )
+ $data .= pack( 'N', $opacity );
+
+
+ $image = array(
+ 'width' => $width,
+ 'height' => $height,
+ 'color_palette_colors' => 0,
+ 'bits_per_pixel' => 32,
+ 'size' => $image_header_size + $color_mask_size + $opacity_mask_size,
+ 'data' => $data,
+ );
+
+ $this->_images[] = $image;
+ }
+
+ /**
+ * Read in the source image file and convert it into a GD image resource.
+ *
+ * @access private
+ */
+ function _load_image_file( $file ) {
+ // Run a cheap check to verify that it is an image file.
+ if ( false === ( $size = getimagesize( $file ) ) )
+ return false;
+
+ if ( false === ( $file_data = file_get_contents( $file ) ) )
+ return false;
+
+ if ( false === ( $im = imagecreatefromstring( $file_data ) ) )
+ return false;
+
+ unset( $file_data );
+
+
+ return $im;
+ }
+}