Skip to content

Commit a4f46c8

Browse files
committed
initial commit
0 parents  commit a4f46c8

20 files changed

+617
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/.idea
2+
/output
3+
/composer.lock
4+
/vendor

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Genkgo/Favicon - Generate favicon for your website
2+
3+
[![Latest Version](https://img.shields.io/github/release/genkgo/favicon.svg?style=flat-square)](https://github.com/genkgo/favicon/releases)
4+
5+
## Create favicon package quick and easy
6+
7+
```php
8+
9+
use Genkgo\Favicon;
10+
11+
$outputDirectory = '/var/www/html/favicon';
12+
13+
$input = Input::fromFile('/var/www/html/logo.png', InputImageType::PNG);
14+
// or
15+
$input = Input::fromFile('/var/www/html/logo.svg', InputImageType::SVG);
16+
// or
17+
$input = Favicon\Input::letter('G', '#FFFFFF', '#00aaad');
18+
19+
$generator = new Favicon\FullPackageGenerator($input, '#FFFFFF');
20+
foreach ($generator->package() as $fileName => $contents) {
21+
$pathName = $outputDirectory . '/' . $fileName;
22+
file_put_contents($pathName, $contents);
23+
}
24+
```
25+
26+
## Default package
27+
28+
- android-chrome-192x192.png
29+
- android-chrome-512x512.png
30+
- apple-touch-icon.png
31+
- browserconfig.xml
32+
- favicon.ico
33+
- favicon.png
34+
- favicon-16x16.png
35+
- favicon-32x32.png
36+
- favicon-48x48.ico
37+
- favicon-48x48.png
38+
- favicon-57x57.png
39+
- favicon-76x76.png
40+
- favicon-96x96.png
41+
- favicon-128x128.png
42+
- favicon-192x192.png
43+
- favicon-228x228.png
44+
- mstile-70x70.png
45+
- mstile-150x150.png
46+
- mstile-310x310.png
47+
48+
## Tests
49+
50+
There are no tests.

asset/genkgo-icon-1024.png

52.1 KB
Loading

asset/genkgo-rondo-1024.svg

Lines changed: 45 additions & 0 deletions
Loading

bin/favicon-generator

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env php
2+
<?php
3+
declare(strict_types=1);
4+
5+
use Genkgo\Favicon\AggregatePackage;
6+
use Genkgo\Favicon\AndroidChromePackage;
7+
use Genkgo\Favicon\AppleTouchIconPackage;
8+
use Genkgo\Favicon\FullPackageGenerator;
9+
use Genkgo\Favicon\GenericIcoPackage;
10+
use Genkgo\Favicon\GenericPngPackage;
11+
use Genkgo\Favicon\MicrosoftTilePackage;
12+
use Genkgo\Favicon\Input;
13+
use Genkgo\Favicon\InputImageType;
14+
15+
function writeln(string $line, string|int ... $values) {
16+
echo sprintf($line, ...$values) . "\n";
17+
}
18+
19+
(function ($arguments) {
20+
error_reporting(-1);
21+
22+
$dir = __DIR__.'/..';
23+
24+
if (!file_exists($dir.'/autoload.php')) {
25+
$dir = __DIR__.'/../vendor';
26+
}
27+
28+
if (!file_exists($dir.'/autoload.php')) {
29+
$dir = __DIR__.'/../../..';
30+
}
31+
32+
if (!file_exists($dir.'/autoload.php')) {
33+
writeln('Autoload not found.');
34+
exit(1);
35+
}
36+
37+
require $dir.'/autoload.php';
38+
39+
if (!array_key_exists(1, $arguments)) {
40+
writeln('[ERROR] Source image is required');
41+
exit(1);
42+
}
43+
44+
$sourceFile = $arguments[1];
45+
if (!file_exists($sourceFile)) {
46+
writeln('[ERROR] Source image %s does not exist', $sourceFile);
47+
exit(1);
48+
}
49+
50+
// $input = Input::fromFile($sourceFile, InputImageType::PNG);
51+
$input = Input::letter('G', '#FFFFFF', '#00aaad');
52+
$outputDirectory = $arguments[2] ?? getcwd();
53+
$tileColor = $arguments[3] ?? '#FFFFFF';
54+
$rootPrefix = $arguments[4] ?? '/';
55+
56+
$generator = new FullPackageGenerator($input, $tileColor, $rootPrefix);
57+
foreach ($generator->package() as $fileName => $contents) {
58+
$pathName = $outputDirectory . '/' . $fileName;
59+
$result = file_put_contents($pathName, $contents);
60+
if ($result === false) {
61+
writeln('[ERROR] Failed to save %s', $pathName);
62+
} else {
63+
writeln('[INFO] Saved %s with size %s', $pathName, filesize($pathName));
64+
}
65+
}
66+
})($argv);

composer.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "genkgo/favicon",
3+
"description": "Generate browser favicons",
4+
"license": "MIT",
5+
"require": {
6+
"php": "~8.1.0 || ~8.2.0",
7+
"ext-imagick": "*",
8+
"ext-dom": "*"
9+
},
10+
"autoload": {
11+
"psr-4": {
12+
"Genkgo\\Favicon\\": ["src"]
13+
}
14+
},
15+
"autoload-dev": {
16+
"psr-4": {
17+
"Genkgo\\TestFavicon\\": ["test"]
18+
}
19+
}
20+
}

src/AggregatePackage.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class AggregatePackage implements PackageAppendInterface
8+
{
9+
/**
10+
* @param iterable<int|string, PackageAppendInterface> $generators
11+
*/
12+
public function __construct(private readonly iterable $generators)
13+
{
14+
}
15+
16+
/**
17+
* @return \Generator<string, string>
18+
*/
19+
public function package(): \Generator
20+
{
21+
foreach ($this->generators as $generator) {
22+
yield from $generator->package();
23+
}
24+
}
25+
}

src/AndroidChromePackage.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class AndroidChromePackage implements PackageAppendInterface
8+
{
9+
/**
10+
* @param array<int, int> $sizes
11+
*/
12+
public function __construct(
13+
private readonly Input $input,
14+
private readonly array $sizes = [192, 512],
15+
private readonly ?string $backgroundColor = null,
16+
) {
17+
}
18+
19+
public function package(): \Generator
20+
{
21+
foreach ($this->sizes as $size) {
22+
$generator = new PngGenerator($this->input, $size, $this->backgroundColor);
23+
yield 'android-chrome-' . $size . 'x' . $size . '.png' => $generator->generate();
24+
}
25+
}
26+
}

src/AppleTouchIconPackage.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class AppleTouchIconPackage implements PackageAppendInterface
8+
{
9+
public function __construct(
10+
private readonly Input $input,
11+
private readonly int $size = 180,
12+
private readonly ?string $backgroundColor = null,
13+
) {
14+
}
15+
16+
public function package(): \Generator
17+
{
18+
$generator = new PngGenerator($this->input, $this->size, $this->backgroundColor);
19+
yield 'apple-touch-icon.png' => $generator->generate();
20+
}
21+
}

src/BrowserConfigXmlGenerator.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class BrowserConfigXmlGenerator implements GeneratorInterface
8+
{
9+
public function __construct(
10+
private readonly string $tileColor,
11+
private readonly array $formats,
12+
private readonly string $rootPrefix = '/',
13+
) {
14+
}
15+
16+
public function generate(): string
17+
{
18+
$document = new \DOMDocument('1.0', 'UTF-8');
19+
$document->formatOutput = true;
20+
$root = $document->createElement('browserconfig');
21+
$document->appendChild($root);
22+
23+
$rootPrefix = $this->rootPrefix;
24+
if (\substr($rootPrefix, -1, 1) === '/') {
25+
$rootPrefix = \substr($rootPrefix, 0, -1);
26+
}
27+
28+
$msApplication = $document->createElement('msapplication');
29+
$tile = $document->createElement('tile');
30+
foreach ($this->formats as $size => $file) {
31+
$tileType = $document->createElement($size . 'logo');
32+
$tileType->setAttribute('src', $rootPrefix . '/' . $file);
33+
$tile->appendChild($tileType);
34+
}
35+
36+
$tileColor = $document->createElement('TileColor', $this->tileColor);
37+
$tile->appendChild($tileColor);
38+
$msApplication->appendChild($tile);
39+
40+
$root->appendChild($msApplication);
41+
return $document->saveXML();
42+
}
43+
}

src/FullPackageGenerator.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class FullPackageGenerator implements PackageAppendInterface
8+
{
9+
public function __construct(
10+
private readonly Input $input,
11+
private readonly string $tileColor,
12+
private readonly string $rootPrefix = '/',
13+
) {
14+
}
15+
16+
public function package(): \Generator
17+
{
18+
$generator = new AggregatePackage([
19+
new GenericIcoPackage($this->input),
20+
new GenericPngPackage($this->input),
21+
new AppleTouchIconPackage($this->input),
22+
new AndroidChromePackage($this->input),
23+
new MicrosoftTilePackage($this->input, $this->tileColor, $this->rootPrefix),
24+
]);
25+
return $generator->package();
26+
}
27+
}

src/GeneratorInterface.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
interface GeneratorInterface
8+
{
9+
/**
10+
* @throws \ImagickException
11+
*/
12+
public function generate(): string;
13+
}

src/GenericIcoPackage.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Genkgo\Favicon;
6+
7+
final class GenericIcoPackage implements PackageAppendInterface
8+
{
9+
/**
10+
* @param array<int, int> $sizes
11+
*/
12+
public function __construct(
13+
private readonly Input $input,
14+
private readonly array $sizes = [48],
15+
private readonly ?string $backgroundColor = null,
16+
) {
17+
}
18+
19+
public function package(): \Generator
20+
{
21+
$first = true;
22+
foreach ($this->sizes as $size) {
23+
$generator = new IcoGenerator($this->input, $size, $this->backgroundColor);
24+
$blob = $generator->generate();
25+
if ($first) {
26+
yield 'favicon.ico' => $blob;
27+
}
28+
29+
$first = false;
30+
yield 'favicon-' . $size . 'x' . $size . '.ico' => $blob;
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)