Compare commits
10
Commits
bb6177811b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0d4d2d989 | ||
|
|
9871e574d5 | ||
|
|
24b11a4033 | ||
|
|
25cd72190d | ||
|
|
d2e7e11e59 | ||
|
|
23585f58a8 | ||
|
|
2f3c65ae9f | ||
|
|
61400ce031 | ||
|
|
689231d94a | ||
|
|
51d7b25cba |
@@ -2,4 +2,7 @@
|
|||||||
*.jpeg
|
*.jpeg
|
||||||
*.png
|
*.png
|
||||||
*.mp4
|
*.mp4
|
||||||
|
./imgs/*
|
||||||
|
imgs/
|
||||||
|
glitch_img
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ffmpegGenerateMP4(fileExt string) {
|
||||||
|
inputPattern := "./output/img_glitched_%d." + fileExt
|
||||||
|
outputVideo := "output.mp4"
|
||||||
|
|
||||||
|
cmd := exec.Command(
|
||||||
|
"ffmpeg",
|
||||||
|
"-y",
|
||||||
|
"-framerate", "30",
|
||||||
|
"-i", inputPattern,
|
||||||
|
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,setpts=PTS*2.0", // Scale and slow down playback
|
||||||
|
"-vcodec", "libx264", // Use H.264 codec
|
||||||
|
"-pix_fmt", "yuv420p",
|
||||||
|
"-crf", "23", // Compression level: lower is higher quality (range: 18-28)
|
||||||
|
"-preset", "fast",
|
||||||
|
outputVideo,
|
||||||
|
)
|
||||||
|
|
||||||
|
done := make(chan bool)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := cmd.Run()
|
||||||
|
check(err, "cannot run ffmpeg command!")
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
msg := "Generating MP4"
|
||||||
|
c := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
fmt.Printf("\r%s%s", msg, dots(c))
|
||||||
|
c = (c + 1)
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
<-done
|
||||||
|
fmt.Println("\nGIF successfully created in ./output.mp4!")
|
||||||
|
}
|
||||||
@@ -7,17 +7,16 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeOutputDir() {
|
func fillSliceWithASCII(slice []byte) {
|
||||||
// Default to just "output"
|
const asciiMin = 16
|
||||||
err := os.Mkdir("output", 0755)
|
const asciiMax = 150
|
||||||
check(err, "cannot make directory")
|
|
||||||
|
for i := range slice {
|
||||||
|
slice[i] = byte(rand.Int32N(asciiMax-asciiMin+1) + asciiMin)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func glitchImage(inputFile string, outputFile string, shitSize int64, iterations int64) error {
|
func glitchImage(inputFile string, outputFile string, shitSize int64, iterations int64) error {
|
||||||
// Ensure the output directory exists
|
|
||||||
makeOutputDir()
|
|
||||||
|
|
||||||
// Prepend the "output" directory to the output file
|
|
||||||
outputFilePath := filepath.Join("output", outputFile)
|
outputFilePath := filepath.Join("output", outputFile)
|
||||||
|
|
||||||
// Open the source file for reading
|
// Open the source file for reading
|
||||||
@@ -40,6 +39,10 @@ func glitchImage(inputFile string, outputFile string, shitSize int64, iterations
|
|||||||
|
|
||||||
// Get the size of the destination file
|
// Get the size of the destination file
|
||||||
fileSize := fileInfo.Size()
|
fileSize := fileInfo.Size()
|
||||||
|
if fileSize == 0 {
|
||||||
|
fmt.Println("Cannot glitch file with size of zero bytes!")
|
||||||
|
return fmt.Errorf("input file is zero bytes")
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a random offset within the file
|
// Generate a random offset within the file
|
||||||
var i int64
|
var i int64
|
||||||
@@ -52,6 +55,7 @@ func glitchImage(inputFile string, outputFile string, shitSize int64, iterations
|
|||||||
|
|
||||||
// Generate random data and write it in
|
// Generate random data and write it in
|
||||||
shit := make([]byte, shitSize)
|
shit := make([]byte, shitSize)
|
||||||
|
fillSliceWithASCII(shit)
|
||||||
_, err = destination.Write(shit)
|
_, err = destination.Write(shit)
|
||||||
check(err, "failed to write shit data: %w")
|
check(err, "failed to write shit data: %w")
|
||||||
|
|
||||||
@@ -60,9 +64,6 @@ func glitchImage(inputFile string, outputFile string, shitSize int64, iterations
|
|||||||
}
|
}
|
||||||
|
|
||||||
func copyImage(inputFile string, outputFile string) error {
|
func copyImage(inputFile string, outputFile string) error {
|
||||||
// Ensure the output directory exists
|
|
||||||
makeOutputDir()
|
|
||||||
|
|
||||||
// Prepend the "output" directory to the output file
|
// Prepend the "output" directory to the output file
|
||||||
outputFilePath := filepath.Join("output", outputFile)
|
outputFilePath := filepath.Join("output", outputFile)
|
||||||
|
|
||||||
@@ -80,22 +81,28 @@ func copyImage(inputFile string, outputFile string) error {
|
|||||||
_, err = destination.ReadFrom(source)
|
_, err = destination.ReadFrom(source)
|
||||||
check(err, "failed to copy file contents: %w")
|
check(err, "failed to copy file contents: %w")
|
||||||
|
|
||||||
|
// no errors
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateGlitchedSequence(inputFile string, totalImages int, shitSize int64, iterations int64) {
|
func generateGlitchedSequence(inputFile string, fileExt string, totalImages int, shitSize int64, iterations int64, chanceToRandom int32) error {
|
||||||
for i := 1; i <= totalImages; i++ {
|
for i := 1; i <= totalImages; i++ {
|
||||||
outputFileName := fmt.Sprintf("img_glitched_%d.jpeg", i) // Generate unique filenames
|
outputFileName := fmt.Sprintf("img_glitched_%d.%s", i, fileExt)
|
||||||
|
|
||||||
// Randomly decide whether to glitch or copy the image
|
if rand.Int32N(100) < chanceToRandom {
|
||||||
if rand.Int32N(2) == 0 {
|
|
||||||
// Glitched image
|
// Glitched image
|
||||||
err := glitchImage(inputFile, outputFileName, shitSize, iterations)
|
err := glitchImage(inputFile, outputFileName, shitSize, iterations)
|
||||||
check(err, "failed to glitch image: %w")
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot glitch image")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Normal image
|
// Normal image
|
||||||
err := copyImage(inputFile, outputFileName)
|
err := copyImage(inputFile, outputFileName)
|
||||||
check(err, "failed to copy normal image: %w")
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot glitch image")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// no errors
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -2,22 +2,29 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
// TODO:
|
||||||
rand.Seed(time.Now().UnixNano())
|
// - Flags instead of os.Args
|
||||||
|
// - Interactive UI
|
||||||
|
// - Check compatability with other image types (PNG etc)
|
||||||
|
// - better ffmpeg bindings (go package?)
|
||||||
|
// - Update README
|
||||||
|
|
||||||
if len(os.Args) < 5 {
|
const MAX_SIZE = 1000000
|
||||||
fmt.Println("Usage: go run main.go <source-file> <number-of-copies> <shit-size> <iterations>")
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 6 {
|
||||||
|
fmt.Println("Usage: ./glitch.go <source-file> <number-of-copies> <shit-size> <iterations> <chance-to-random % (0-100)>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceFile := os.Args[1]
|
sourceFile := os.Args[1]
|
||||||
|
fileExt := filepath.Ext(sourceFile)
|
||||||
|
|
||||||
numCopies, err := strconv.Atoi(os.Args[2])
|
numCopies, err := strconv.Atoi(os.Args[2])
|
||||||
if err != nil || numCopies <= 0 {
|
if err != nil || numCopies <= 0 {
|
||||||
fmt.Println("Invalid number of copies. Must be a positive integer.")
|
fmt.Println("Invalid number of copies. Must be a positive integer.")
|
||||||
@@ -28,65 +35,32 @@ func main() {
|
|||||||
if err != nil || shitSize <= 0 {
|
if err != nil || shitSize <= 0 {
|
||||||
fmt.Println("Invalid shit size. Must be a positive integer.")
|
fmt.Println("Invalid shit size. Must be a positive integer.")
|
||||||
return
|
return
|
||||||
|
} else if shitSize > MAX_SIZE {
|
||||||
|
fmt.Printf("shitSize exceeds maximum size (%d)\n", MAX_SIZE)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
iterations, err := strconv.ParseInt(os.Args[4], 10, 8)
|
iterations, err := strconv.ParseInt(os.Args[4], 10, 8)
|
||||||
|
check(err, "Cannot parse iterations. Must be a positive integer")
|
||||||
|
|
||||||
/*
|
chanceToRandom, err := strconv.ParseInt(os.Args[5], 10, 32)
|
||||||
for i := 1; i <= numCopies; i++ {
|
if err != nil || chanceToRandom < 0 {
|
||||||
outputFile := fmt.Sprintf("%s_glitched_%d%s",
|
fmt.Println("Invalid random chance value. Must be a positive integer (0-100).")
|
||||||
stripExtension(sourceFile),
|
return
|
||||||
i,
|
} else if chanceToRandom > 100 {
|
||||||
filepath.Ext(sourceFile),
|
fmt.Println("Invalid random chance value. Must range between 0 to 100.")
|
||||||
)
|
|
||||||
|
|
||||||
err := glitchImage(sourceFile, outputFile, shitSize, iterations)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error glitching file %d: %v\n", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
generateGlitchedSequence(sourceFile, numCopies, shitSize, iterations)
|
|
||||||
|
|
||||||
inputPattern := "./output/img_glitched_%d.jpeg"
|
|
||||||
outputVideo := "output.mp4"
|
|
||||||
|
|
||||||
cmd := exec.Command(
|
|
||||||
"ffmpeg",
|
|
||||||
"-y",
|
|
||||||
"-framerate", "30",
|
|
||||||
"-i", inputPattern,
|
|
||||||
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,setpts=PTS*2.0", // Scale and slow down playback
|
|
||||||
"-vcodec", "libx264", // Use H.264 codec
|
|
||||||
"-pix_fmt", "yuv420p",
|
|
||||||
"-crf", "23", // Compression level: lower is higher quality (range: 18-28)
|
|
||||||
"-preset", "fast",
|
|
||||||
outputVideo,
|
|
||||||
)
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
err := cmd.Run()
|
|
||||||
check(err, "cannot run ffmpeg command!")
|
|
||||||
done <- true
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
msg := "Generating MP4"
|
|
||||||
c := 0
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
return
|
return
|
||||||
default:
|
|
||||||
fmt.Printf("\r%s%s", msg, dots(c))
|
|
||||||
c = (c + 1)
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stdout, "Generating:\n %d copies of %s\n %d random bytes of data\n %d interations(s)\n Chance to random %d%%\n File Extention: %s\n\n",
|
||||||
|
numCopies, sourceFile, shitSize, iterations, chanceToRandom, fileExt)
|
||||||
|
|
||||||
|
makeOutputDir()
|
||||||
|
defer clearOutputDir()
|
||||||
|
|
||||||
|
err = generateGlitchedSequence(sourceFile, fileExt, numCopies, shitSize, iterations, int32(chanceToRandom))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}()
|
ffmpegGenerateMP4(fileExt)
|
||||||
<-done
|
|
||||||
fmt.Println("\nGIF successfully created in ./output.mp4!")
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,3 +24,23 @@ func stripExtension(filename string) string {
|
|||||||
ext := filepath.Ext(filename)
|
ext := filepath.Ext(filename)
|
||||||
return filename[:len(filename)-len(ext)]
|
return filename[:len(filename)-len(ext)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeOutputDir() {
|
||||||
|
// Default to just "output"
|
||||||
|
err := os.Mkdir("output", 0755)
|
||||||
|
check(err, "cannot make directory")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearOutputDir() {
|
||||||
|
err := os.RemoveAll("./output")
|
||||||
|
check(err, "cannot remove directory")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage() {
|
||||||
|
fmt.Println("Usage: go run main.go <source-file> <number-of-copies> <shit-size> <iterations>")
|
||||||
|
fmt.Println(`
|
||||||
|
source-file:
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user