11#!/usr/bin/env node
22"use strict" ;
33
4- const Clipper = require ( "image-clipper" ) ;
5- const canvas = require ( "canvas" ) ;
6- const { GifFrame, GifUtil } = require ( "gifwrap" ) ;
4+ const { GifFrame, GifUtil, BitmapImage } = require ( "gifwrap" ) ;
75const Jimp = require ( "jimp" ) ;
86const updateNotifier = require ( "update-notifier" ) ;
97const meow = require ( "meow" ) ;
108
9+ const CONTAINER_WIDTH = 727 ;
10+ const CUT_WIDTH = 325 ;
11+ const CUT_HEIGHT = 100 ;
12+ const CARD_PADDING_TOP = 37 ;
13+ const CARD_PADDING_HORIZONTAL = 16 ;
14+ const CARD_PADDING_BOTTOM = 16 ;
15+ const CARD_MARGIN_BOTTOM = 16 ;
16+ const CARD_HEIGHT = CARD_PADDING_TOP + CUT_HEIGHT + CARD_PADDING_BOTTOM ;
17+ const Y_OFFSET = CARD_HEIGHT + CARD_MARGIN_BOTTOM ;
18+ const MINIMUM_HEIGHT = 3 * CARD_HEIGHT + 2 * CARD_MARGIN_BOTTOM ;
19+
1120const cli = meow (
1221 `
1322 Usage
@@ -23,66 +32,94 @@ const cli = meow(
2332updateNotifier ( { pkg : cli . pkg } ) . notify ( ) ;
2433
2534if ( cli . input . length === 0 ) {
26- console . error ( "Specify at least one path" ) ;
35+ console . error ( "Specify exactly one path to the image/gif " ) ;
2736 process . exit ( 1 ) ;
2837}
2938
30- const cropGithubGifs = path => {
31- const GIF_WIDTH = 325 ;
32- const GIF_HEIGHT = 100 ;
33- const VERTICAL_MARGIN = 53 ;
34- const HORIZONTAL_MARGIN = 32 ;
35-
36- GifUtil . read ( path )
37- . then ( source => {
38- let croppedGifs = [ ] ;
39-
40- for ( let i = 0 ; i < 6 ; i ++ ) {
41- const isLeft = i % 2 === 0 ;
42- const x = isLeft ? 0 : GIF_WIDTH + HORIZONTAL_MARGIN ;
43- const y = Math . floor ( i / 2 ) * ( GIF_HEIGHT + VERTICAL_MARGIN ) ;
44-
45- let gif = [ ] ;
46- for ( let frame = 0 ; frame < source . frames . length ; frame ++ ) {
47- let j = new Jimp (
48- source . frames [ frame ] . bitmap . width ,
49- source . frames [ frame ] . bitmap . height ,
50- 0
51- ) ;
52- j . bitmap . data = source . frames [ frame ] . bitmap . data ;
53- j . resize ( GIF_WIDTH * 2 + HORIZONTAL_MARGIN , GIF_HEIGHT * 3 + VERTICAL_MARGIN * 2 )
54- . crop ( x , y , GIF_WIDTH , GIF_HEIGHT ) ;
55- gif [ frame ] = new GifFrame ( j . bitmap ) ;
56- }
57- croppedGifs . push ( gif ) ;
58- }
59-
60- croppedGifs . forEach ( ( gif , i ) => {
61- GifUtil . quantizeDekker ( gif ) ;
62- GifUtil . write ( `${ i } .gif` , gif ) . then ( result => {
63- console . log ( `saved ${ i } .gif` ) ;
64- } ) ;
65- } ) ;
66- } )
67- . catch ( console . error ) ;
39+ const getXY = index => {
40+ const isLeft = index % 2 === 0 ;
41+ // There is no margin between cards, instead, they are
42+ // separated by flex's space-between, which is directly
43+ // affected by container width. When someday container
44+ // width changes, we can just change its value and this
45+ // method will be fixed.
46+ const x = isLeft
47+ ? CARD_PADDING_HORIZONTAL
48+ : CONTAINER_WIDTH - ( CARD_PADDING_HORIZONTAL + CUT_WIDTH ) ;
49+ const indexFromTop = Math . floor ( index / 2 ) ;
50+ const y = CARD_PADDING_TOP + indexFromTop * Y_OFFSET ;
51+ return { x, y } ;
52+ } ;
53+
54+ const cropFrame = image => {
55+ const cropped = [ ] ;
56+ for ( let i = 0 ; i < 6 ; i ++ ) {
57+ const clone = image . clone ( ) ;
58+ const { x, y } = getXY ( i ) ;
59+ clone . crop ( x , y , CUT_WIDTH , CUT_HEIGHT ) ;
60+ cropped . push ( clone ) ;
61+ }
62+ return cropped ;
6863} ;
6964
70- const WIDTH = 727 ;
71- const INTERVAL = 171 ;
65+ const cropGithubGifs = async path => {
66+ try {
67+ const source = await GifUtil . read ( path ) ;
68+ const { frames } = source ;
69+ let croppedGifs = [ ] ;
70+ let frameIndex = 1 ;
71+ for ( const frame of frames ) {
72+ console . log ( `Processing frame ${ frameIndex } of ${ frames . length } ` ) ;
73+ const buf = frame . bitmap . data ;
74+ frame . scanAllCoords ( ( x , y , bi ) => {
75+ buf [ bi + 3 ] = 0xff ;
76+ } ) ;
7277
73- const cropGithubImages = path => {
74- const clipper = Clipper ( { canvas } ) ;
78+ let jimpToCrop = new Jimp ( frame . bitmap . width , frame . bitmap . height , 0 ) ;
79+ jimpToCrop . bitmap . data = frame . bitmap . data ;
80+ jimpToCrop . resize ( CONTAINER_WIDTH , Jimp . AUTO ) ;
7581
76- for ( let i = 0 ; i < 6 ; i ++ ) {
77- const isLeft = i % 2 === 0 ;
78- const x = isLeft ? 16 : WIDTH - 16 - 325 ;
79- const y = 53 + INTERVAL * Math . floor ( i / 2 + 0.1 ) ;
80- clipper . image ( path , function ( ) {
81- const name = `${ i } .jpg` ;
82- this . crop ( x , y , 325 , 100 ) . toFile ( `./${ name } ` , function ( ) {
83- console . log ( `saved ${ name } ` ) ;
82+ const frameToCrop = await Jimp . read ( jimpToCrop ) ;
83+
84+ const cropped = cropFrame ( frameToCrop ) . map ( img => {
85+ return new GifFrame ( img . bitmap ) ;
8486 } ) ;
87+
88+ cropped . forEach ( ( croppedFrame , i ) => {
89+ croppedFrame . scanAllCoords ( ( x , y , bi ) => {
90+ buf [ bi + 3 ] = 0xff ;
91+ } ) ;
92+ croppedGifs [ i ] = croppedGifs [ i ]
93+ ? [ ...croppedGifs [ i ] , croppedFrame ]
94+ : [ croppedFrame ] ;
95+ } ) ;
96+
97+ frameIndex ++ ;
98+ }
99+
100+ croppedGifs . forEach ( async ( croppedFrames , i ) => {
101+ console . log (
102+ `Quantizing Dekker value for gif ${ i } (this might take a while)`
103+ ) ;
104+ GifUtil . quantizeDekker ( croppedFrames ) ;
105+ await GifUtil . write ( `${ i } .gif` , croppedFrames ) ;
106+ console . log ( `saved ${ i } .gif` ) ;
85107 } ) ;
108+ } catch ( error ) {
109+ console . error ( error ) ;
110+ }
111+ } ;
112+
113+ const cropGithubImages = async path => {
114+ const image = await Jimp . read ( path ) ;
115+
116+ image . resize ( CONTAINER_WIDTH , Jimp . AUTO ) ;
117+ const cropped = cropFrame ( image ) ;
118+
119+ for ( let i = 0 ; i < cropped . length ; i ++ ) {
120+ const clone = cropped [ i ] ;
121+ await clone . writeAsync ( `${ i } .jpg` ) ;
122+ console . log ( i , "has been written." ) ;
86123 }
87124} ;
88125
0 commit comments