Skip to content

Instantly share code, notes, and snippets.

@brunob
Created May 8, 2020 13:11
Show Gist options
  • Save brunob/055fac68c1283b6d89ee7a1e3f2a9fd6 to your computer and use it in GitHub Desktop.
Save brunob/055fac68c1283b6d89ee7a1e3f2a9fd6 to your computer and use it in GitHub Desktop.
Tramer des images avec SPIP / https://seenthis.net/messages/823602
<style type="text/css">
@media (min-width:576px){[class*=" grid-"],[class^=grid-]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap}[class*=" grid-"]>*,[class^=grid-]>*{-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0;min-height:0}}@media (min-width:576px){.grid,.grid--reverse{display:-webkit-box;display:-ms-flexbox;display:flex}.grid--reverse>*,.grid>*{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0;min-height:0}.grid--reverse.has-gutter>*+*,.grid.has-gutter>*+*{margin-left:calc(1rem - .01px)}.grid--reverse.has-gutter-l>*+*,.grid.has-gutter-l>*+*{margin-left:calc(2rem - .01px)}.grid--reverse.has-gutter-xl>*+*,.grid.has-gutter-xl>*+*{margin-left:calc(4rem - .01px)}}@media (min-width:576px){[class*=grid-2]>*{width:calc(100% / 2 - .01px)}[class*=grid-2].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-2].has-gutter>*{width:calc(100% / 2 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-2].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-2].has-gutter-l>*{width:calc(100% / 2 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-2].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-2].has-gutter-xl>*{width:calc(100% / 2 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-3]>*{width:calc(100% / 3 - .01px)}[class*=grid-3].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-3].has-gutter>*{width:calc(100% / 3 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-3].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-3].has-gutter-l>*{width:calc(100% / 3 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-3].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-3].has-gutter-xl>*{width:calc(100% / 3 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-4]>*{width:calc(100% / 4 - .01px)}[class*=grid-4].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-4].has-gutter>*{width:calc(100% / 4 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-4].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-4].has-gutter-l>*{width:calc(100% / 4 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-4].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-4].has-gutter-xl>*{width:calc(100% / 4 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-5]>*{width:calc(100% / 5 - .01px)}[class*=grid-5].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-5].has-gutter>*{width:calc(100% / 5 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-5].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-5].has-gutter-l>*{width:calc(100% / 5 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-5].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-5].has-gutter-xl>*{width:calc(100% / 5 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-6]>*{width:calc(100% / 6 - .01px)}[class*=grid-6].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-6].has-gutter>*{width:calc(100% / 6 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-6].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-6].has-gutter-l>*{width:calc(100% / 6 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-6].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-6].has-gutter-xl>*{width:calc(100% / 6 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-7]>*{width:calc(100% / 7 - .01px)}[class*=grid-7].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-7].has-gutter>*{width:calc(100% / 7 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-7].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-7].has-gutter-l>*{width:calc(100% / 7 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-7].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-7].has-gutter-xl>*{width:calc(100% / 7 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-8]>*{width:calc(100% / 8 - .01px)}[class*=grid-8].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-8].has-gutter>*{width:calc(100% / 8 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-8].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-8].has-gutter-l>*{width:calc(100% / 8 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-8].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-8].has-gutter-xl>*{width:calc(100% / 8 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-9]>*{width:calc(100% / 9 - .01px)}[class*=grid-9].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-9].has-gutter>*{width:calc(100% / 9 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-9].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-9].has-gutter-l>*{width:calc(100% / 9 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-9].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-9].has-gutter-xl>*{width:calc(100% / 9 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-10]>*{width:calc(100% / 10 - .01px)}[class*=grid-10].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-10].has-gutter>*{width:calc(100% / 10 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-10].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-10].has-gutter-l>*{width:calc(100% / 10 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-10].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-10].has-gutter-xl>*{width:calc(100% / 10 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-11]>*{width:calc(100% / 11 - .01px)}[class*=grid-11].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-11].has-gutter>*{width:calc(100% / 11 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-11].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-11].has-gutter-l>*{width:calc(100% / 11 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-11].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-11].has-gutter-xl>*{width:calc(100% / 11 - 4rem - .01px);margin-right:2rem;margin-left:2rem}[class*=grid-12]>*{width:calc(100% / 12 - .01px)}[class*=grid-12].has-gutter{margin-right:-.5rem;margin-left:-.5rem}[class*=grid-12].has-gutter>*{width:calc(100% / 12 - 1rem - .01px);margin-right:.5rem;margin-left:.5rem}[class*=grid-12].has-gutter-l{margin-right:-1rem;margin-left:-1rem}[class*=grid-12].has-gutter-l>*{width:calc(100% / 12 - 2rem - .01px);margin-right:1rem;margin-left:1rem}[class*=grid-12].has-gutter-xl{margin-right:-2rem;margin-left:-2rem}[class*=grid-12].has-gutter-xl>*{width:calc(100% / 12 - 4rem - .01px);margin-right:2rem;margin-left:2rem}}.push{margin-left:auto!important}.pull{margin-right:auto!important}.item-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.item-last{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}[class*=grid-][class*="--reverse"]{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}@media (min-width:576px){.full{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 1 - .01px)}.has-gutter>.full{width:calc(100% / 1 - 1rem - .01px)}.has-gutter-l>.full{width:calc(100% / 1 - 2rem - .01px)}.has-gutter-xl>.full{width:calc(100% / 1 - 4rem - .01px)}.one-half{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 2 - .01px)}.has-gutter>.one-half{width:calc(100% / 2 - 1rem - .01px)}.has-gutter-l>.one-half{width:calc(100% / 2 - 2rem - .01px)}.has-gutter-xl>.one-half{width:calc(100% / 2 - 4rem - .01px)}.one-third{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 3 - .01px)}.has-gutter>.one-third{width:calc(100% / 3 - 1rem - .01px)}.has-gutter-l>.one-third{width:calc(100% / 3 - 2rem - .01px)}.has-gutter-xl>.one-third{width:calc(100% / 3 - 4rem - .01px)}.one-quarter{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 4 - .01px)}.has-gutter>.one-quarter{width:calc(100% / 4 - 1rem - .01px)}.has-gutter-l>.one-quarter{width:calc(100% / 4 - 2rem - .01px)}.has-gutter-xl>.one-quarter{width:calc(100% / 4 - 4rem - .01px)}.one-fifth{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 5 - .01px)}.has-gutter>.one-fifth{width:calc(100% / 5 - 1rem - .01px)}.has-gutter-l>.one-fifth{width:calc(100% / 5 - 2rem - .01px)}.has-gutter-xl>.one-fifth{width:calc(100% / 5 - 4rem - .01px)}.one-sixth{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 6 - .01px)}.has-gutter>.one-sixth{width:calc(100% / 6 - 1rem - .01px)}.has-gutter-l>.one-sixth{width:calc(100% / 6 - 2rem - .01px)}.has-gutter-xl>.one-sixth{width:calc(100% / 6 - 4rem - .01px)}.two-thirds{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 3 * 2 - .01px)}.has-gutter>.two-thirds{width:calc(100% / 3 * 2 - 1rem - .01px)}.has-gutter-l>.two-thirds{width:calc(100% / 3 * 2 - 2rem - .01px)}.has-gutter-xl>.two-thirds{width:calc(100% / 3 * 2 - 4rem - .01px)}.three-quarters{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 4 * 3 - .01px)}.has-gutter>.three-quarters{width:calc(100% / 4 * 3 - 1rem - .01px)}.has-gutter-l>.three-quarters{width:calc(100% / 4 * 3 - 2rem - .01px)}.has-gutter-xl>.three-quarters{width:calc(100% / 4 * 3 - 4rem - .01px)}.five-sixths{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:calc(100% / 6 * 5 - .01px)}.has-gutter>.five-sixths{width:calc(100% / 6 * 5 - 1rem - .01px)}.has-gutter-l>.five-sixths{width:calc(100% / 6 * 5 - 2rem - .01px)}.has-gutter-xl>.five-sixths{width:calc(100% / 6 * 5 - 4rem - .01px)}}@media (min-width:576px) and (max-width:767px){[class*="-small-1"]>*{width:calc(100% / 1 - .01px)}[class*="-small-1"].has-gutter>*{width:calc(100% / 1 - 1rem - .01px)}[class*="-small-1"].has-gutter-l>*{width:calc(100% / 1 - 2rem - .01px)}[class*="-small-1"].has-gutter-xl>*{width:calc(100% / 1 - 4rem - .01px)}[class*="-small-2"]>*{width:calc(100% / 2 - .01px)}[class*="-small-2"].has-gutter>*{width:calc(100% / 2 - 1rem - .01px)}[class*="-small-2"].has-gutter-l>*{width:calc(100% / 2 - 2rem - .01px)}[class*="-small-2"].has-gutter-xl>*{width:calc(100% / 2 - 4rem - .01px)}[class*="-small-3"]>*{width:calc(100% / 3 - .01px)}[class*="-small-3"].has-gutter>*{width:calc(100% / 3 - 1rem - .01px)}[class*="-small-3"].has-gutter-l>*{width:calc(100% / 3 - 2rem - .01px)}[class*="-small-3"].has-gutter-xl>*{width:calc(100% / 3 - 4rem - .01px)}[class*="-small-4"]>*{width:calc(100% / 4 - .01px)}[class*="-small-4"].has-gutter>*{width:calc(100% / 4 - 1rem - .01px)}[class*="-small-4"].has-gutter-l>*{width:calc(100% / 4 - 2rem - .01px)}[class*="-small-4"].has-gutter-xl>*{width:calc(100% / 4 - 4rem - .01px)}}
img { display: block; margin: 0 auto; }
.full:not(.original) img { width: 100%; height: auto;}
.text-center { text-align: center; }
</style>
<h1>Tramer !</h1>
<p>Nécessite le plugin https://plugins.spip.net/fonctions_images.html maintenant que le filtre image_tramer y est intégré.</p>
<p>Ref : https://seenthis.net/messages/823602 & https://github.com/lowtechmag/solar/wiki/Solar-Web-Design#dithered-images</p>
#SET{fichier,https://camo.githubusercontent.com/60fafb5f827374ecb37b77c7ed13b23188202b5e/68747470733a2f2f6d617269656f7473756b612e6769746875622e696f2f626c6f672f696d672f73746f6e6566657272792d64657461696c2e706e67}
#SET{taille_big,600}
#SET{taille,300}
<div class="grid-4-small-2 has-gutter text-center">
<div class="full original">
[(#GET{fichier}|balise_img)]
[(#GET{fichier}|copie_locale|filesize|taille_en_octets)]
</div>
<div class="full">
[(#GET{fichier}|image_tramer_gd)]
[image_tramer_gd/ (#GET{fichier}|image_tramer_gd|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<div class="full">
[(#GET{fichier}|image_tramer_floydsteinberg)]
[image_tramer_floydsteinberg / (#GET{fichier}|image_tramer_floydsteinberg|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<div class="full">
[(#GET{fichier}|image_tramer{3})]
[o8x8,3 / (#GET{fichier}|image_tramer{3}|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<div class="full">
[(#GET{fichier}|image_tramer{6})]
[o8x8,6 / (#GET{fichier}|image_tramer{6}|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<div class="full">
[(#GET{fichier}|image_tramer{11})]
[o8x8,11/ (#GET{fichier}|image_tramer{11}|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<div>
[(#GET{fichier}|image_reduire{#GET{taille}})]
[(#GET{fichier}|image_reduire{#GET{taille}}|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
<BOUCLE_data(DATA){liste threshold,checks,o2x2,o3x3,o4x4,o8x8,h4x4a,h6x6a,h8x8a,h4x4o,h6x6o,h8x8o,h16x16o,c5x5b,c5x5w,c6x6b,c6x6w,c7x7b,c7x7w}>
<div>
[(#GET{fichier}|image_reduire{#GET{taille}}|image_tramer{6,#VALEUR})]
[(#VALEUR),6 / ][(#GET{fichier}|image_reduire{#GET{taille}}|image_tramer{6,#VALEUR}|extraire_attribut{src}|supprimer_timestamp|filesize|taille_en_octets)]
</div>
</BOUCLE_data>
</div>
<?php
if (!defined("_ECRIRE_INC_VERSION")) return;
include_spip('inc/filtres_images_lib_mini');
/**
* image_tramer_floydsteinberg necessite d'avoir https://raw.githubusercontent.com/ccpalettes/gd-indexed-color-converter/master/src/GDIndexedColorConverter.php dans squelettes/lib
*
* @param unknown_type $img
* @param array $palette
* @param int $dither le nombre de couleur minimum d'une image non considérée comme monochrome
* @return bool true|false
*/
function image_tramer_floydsteinberg($img, $palette = array(array(25,25,25), array(75,75,75), array(125,125,125), array(175,175,175), array(225,225,225), array(250,250,250)), $dither=0.75){
$cache = _image_valeurs_trans($img, "tramer_floydsteinberg-$dither-".json_encode($palette), 'png');
if (!$cache) {
return false;
}
// facile !
if ($cache['format_source'] === 'svg'){
return $img;
}
$fichier = $cache["fichier"];
$dest = $cache["fichier_dest"];
$creer = $cache["creer"];
if ($creer) {
include_spip('lib/GDIndexedColorConverter');
$im = $cache["fonction_imagecreatefrom"]($fichier);
$converter = new GDIndexedColorConverter();
$im_ = $converter->convertToIndexedColor($im, $palette, $dither);
_image_gd_output($im_, $cache);
imagedestroy($im);
imagedestroy($im_);
}
return _image_ecrire_tag($cache, array('src' => $dest));
}
/**
* image_tramer_gd
*
* @param unknown_type $img
* @param array $palette
* @param int $dither le nombre de couleur minimum d'une image non considérée comme monochrome
* @return bool true|false
*/
function image_tramer_gd($img, $levels = 6){
$cache = _image_valeurs_trans($img, "image_tramer_gd-$levels", 'png');
if (!$cache) {
return false;
}
// facile !
if ($cache['format_source'] === 'svg'){
return $img;
}
$fichier = $cache["fichier"];
$dest = $cache["fichier_dest"];
$largeur = $cache["largeur"];
$hauteur = $cache["hauteur"];
$creer = $cache["creer"];
$threshold_map = array(
array(25,25,25),
array(75,75,75),
array(125,125,125),
array(175,175,175),
array(225,225,225),
array(250,250,250)
);
$threshold_map = array(
array( 15, 135, 45, 165 ),
array( 195, 75, 225, 105 ),
array( 60, 180, 30, 150 ),
array( 240, 120, 210, 90 )
);
if ($creer) {
$im = $cache["fonction_imagecreatefrom"]($fichier);
imagepalettetotruecolor($im);
$im_ = imagecreatetruecolor($largeur, $hauteur);
// https://github.com/kosinix/grafika/blob/master/src/Grafika/Gd/Filter/Dither.php#L135
for ( $y = 0; $y < $hauteur; $y += 1 ) {
for ( $x = 0; $x < $largeur; $x += 1 ) {
$color = imagecolorat( $im, $x, $y );
$r = ( $color >> 16 ) & 0xFF;
$g = ( $color >> 8 ) & 0xFF;
$b = $color & 0xFF;
$gray = round( $r * 0.3 + $g * 0.59 + $b * 0.11 );
$threshold = $threshold_map[ $x % 4 ][ $y % 4 ];
$oldPixel = ( $gray + $threshold ) / 2;
if ( $oldPixel <= 127 ) { // Determine if black or white. Also has the benefit of clipping excess value
$newPixel = 0;
} else {
$newPixel = 255;
}
// Current pixel
imagesetpixel( $im_, $x, $y,
imagecolorallocate( $im_,
$newPixel,
$newPixel,
$newPixel
)
);
}
}
_image_gd_output($im_, $cache);
imagedestroy($im);
imagedestroy($im_);
}
return _image_ecrire_tag($cache, array('src' => $dest));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment