Compare commits

...
12 Commits
Author SHA1 Message Date
Simon Kellet e0d4d2d989 error handling for zero bytes 2025-01-22 19:19:00 +00:00
Simon Kellet 9871e574d5 better glitching algorithm 2025-01-22 19:18:49 +00:00
Simon Kellet 24b11a4033 png support 2025-01-22 18:51:01 +00:00
Simon Kellet 25cd72190d fixed usage 2025-01-22 17:23:56 +00:00
Simon Kellet d2e7e11e59 removed binary 2025-01-22 17:20:40 +00:00
Simon Kellet 23585f58a8 now can add chance to glitch 2025-01-22 17:19:48 +00:00
Simon Kellet 2f3c65ae9f changes 2025-01-14 00:40:22 +00:00
Simon Kellet 61400ce031 ignore changes 2025-01-14 00:11:13 +00:00
Simon Kellet 689231d94a ignore update 2025-01-14 00:10:39 +00:00
Simon Kellet 51d7b25cba clean up and guard checks 2025-01-14 00:08:36 +00:00
Simon Kellet bb6177811b ignore mp4 2025-01-09 19:49:36 +00:00
Simon Kellet e4a5771e18 added new functionality 2025-01-09 19:48:57 +00:00
7 changed files with 180 additions and 34 deletions
+4
View File
@@ -1,4 +1,8 @@
*.gif *.gif
*.jpeg *.jpeg
*.png *.png
*.mp4
./imgs/*
imgs/
glitch_img
.DS_Store .DS_Store
+5 -5
View File
@@ -16,15 +16,15 @@ go build
2. Run the command 2. Run the command
```bash ```bash
$ ./glitch_img $ ./glitch_img
Usage: go run main.go <source-file> <number-of-copies> <shit-size> <iterations> Usage: go run main.go <source-file> <number-of-copies> <shit-size> <iterations>
``` ```
### Example ### Example
```bash ```bash
./glitch*img img.jpeg 100 30 2 ./glitch_img img.jpeg 100 30 2
``` ```
Outputs 100 images into a destination folder _output_ with 30 random bytes of data, running through the file twice Outputs 100 images into a destination folder _output_ with 30 random bytes of data, running through the file twice
+50
View File
@@ -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!")
}
+57 -9
View File
@@ -1,22 +1,22 @@
package main package main
import ( import (
"fmt"
"math/rand/v2" "math/rand/v2"
"os" "os"
"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
@@ -39,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
@@ -51,10 +55,54 @@ 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")
// fmt.Printf("Successfully wrote %d bytes of shit at offset %d in file %s\n", shitSize, offset, outputFilePath)
} }
return nil return nil
} }
func copyImage(inputFile string, outputFile string) error {
// Prepend the "output" directory to the output file
outputFilePath := filepath.Join("output", outputFile)
// Open the source file for reading
source, err := os.Open(inputFile)
check(err, "failed to open source file: %w")
defer source.Close()
// Create a new file for writing the copy
destination, err := os.Create(outputFilePath)
check(err, "failed to create output file: %w")
defer destination.Close()
// Copy the contents of the source file to the destination
_, err = destination.ReadFrom(source)
check(err, "failed to copy file contents: %w")
// no errors
return nil
}
func generateGlitchedSequence(inputFile string, fileExt string, totalImages int, shitSize int64, iterations int64, chanceToRandom int32) error {
for i := 1; i <= totalImages; i++ {
outputFileName := fmt.Sprintf("img_glitched_%d.%s", i, fileExt)
if rand.Int32N(100) < chanceToRandom {
// Glitched image
err := glitchImage(inputFile, outputFileName, shitSize, iterations)
if err != nil {
return fmt.Errorf("Cannot glitch image")
}
} else {
// Normal image
err := copyImage(inputFile, outputFileName)
if err != nil {
return fmt.Errorf("Cannot glitch image")
}
}
}
// no errors
return nil
}
BIN
View File
Binary file not shown.
+35 -20
View File
@@ -3,18 +3,28 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
) )
// TODO:
// - Flags instead of os.Args
// - Interactive UI
// - Check compatability with other image types (PNG etc)
// - better ffmpeg bindings (go package?)
// - Update README
const MAX_SIZE = 1000000
func main() { func main() {
if len(os.Args) < 5 { if len(os.Args) < 6 {
fmt.Println("Usage: go run main.go <source-file> <number-of-copies> <shit-size> <iterations>") 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.")
@@ -25,27 +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")
for i := 1; i <= numCopies; i++ { chanceToRandom, err := strconv.ParseInt(os.Args[5], 10, 32)
outputFile := fmt.Sprintf("%s_glitched_%d%s", if err != nil || chanceToRandom < 0 {
stripExtension(sourceFile), fmt.Println("Invalid random chance value. Must be a positive integer (0-100).")
i, return
filepath.Ext(sourceFile), } else if chanceToRandom > 100 {
) fmt.Println("Invalid random chance value. Must range between 0 to 100.")
return
err := glitchImage(sourceFile, outputFile, shitSize, iterations)
if err != nil {
fmt.Printf("Error glitching file %d: %v\n", i, err)
}
} }
fmt.Println("GENREATING GIF YEAHH ") 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",
// now run ffmpeg to make a gif! numCopies, sourceFile, shitSize, iterations, chanceToRandom, fileExt)
cmd := exec.Command("ffmpeg", "-y", "-framerate 60", "-i", "./output/img_glitched_%d.jpeg output.gif")
err = cmd.Run() makeOutputDir()
check(err, "cannot run ffmpeg command!") defer clearOutputDir()
//
err = generateGlitchedSequence(sourceFile, fileExt, numCopies, shitSize, iterations, int32(chanceToRandom))
if err != nil {
return
}
ffmpegGenerateMP4(fileExt)
} }
+29
View File
@@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
) )
@@ -11,7 +12,35 @@ func check(e error, s string) {
} }
} }
func dots(count int) string {
dotStr := ""
for i := 0; i < count; i++ {
dotStr += "."
}
return dotStr
}
func stripExtension(filename string) string { 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:
`)
}