Skip to content

Commit

Permalink
Path management, loggers, and true pixel size. Readability improvemen…
Browse files Browse the repository at this point in the history
…ts and diverse optimizations
  • Loading branch information
eleby committed Mar 7, 2021
1 parent 32846a8 commit 33effda
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 127 deletions.
54 changes: 42 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,62 @@ $ sudo mv pixelize [your $GOBIN or $GOPATH/bin]
Pixelizer is meant to be simple to use, error-free and intuitive.
To be reminded of the usage, you can sure read this readme, but you can also open your terminal and use :
```
$ pixelize [OR] pixelize help [OR] pixelize man
$ pixelize / $ pixelize man / $ pixelize help
```
This will print the manual.

Here is how it works :
1. Pixelize an image (Basic syntax) :
```
$ pixelize [imageName] [X] [Y] [Z] [...]
```
* imageName = path and name of the image to pixelize.
* X = Width of each group of pixels to fuse (Ex : 5 will fuse every group of 5\*5 pixels from the image)
* Y = Number of results, with increasing X at each result (Ex : 5 3 will print 3 results while fusing groups of 5\*5 pixels for the first result, 6\*6 for the second, etc)
* Z = Change to the step increase between each result (Ex : 5 3 5 will print 3 results while fusing groups of 5\*5 pixels for the first result, 10\*10 for the second, etc)
* ... = Secondary arguments

/!\ The pixelizer needs to be used directly in the folder containing the image. This known limitation may change in the future. /!\
If not set, X, Y and Z will default to 1, meaning that "pixelize img.png" will output one image with a pixelization level of 1.

1. Print the manual :
2. Secondary arguments to add to modify the basic syntax's behavior :

* Log the essential of the program activity in terminal :
```
$ pixelize [OR] pixelize help [OR] pixelize man
$ pixelize [basic syntax] [log]
```
2. Pixelize an image :
* Log more of the program activity in terminal :
```
$ pixelize [imageName] [X] [Y] [Z]
$ pixelize [basic syntax] [verb]
```
* Print every result image in terminal using ANSI codes and register these in the program save directory (HomeDirectory/pixelizer) :
```
$ pixelize [basic syntax] [print]
```
* Reduce the size of the image so each pixelized group of colors will display as a pixel.
```
$ pixelize [basic syntax] [pixel]
```

The pixel argument cannot be used while outputting gifs. If both are specified, only the pixel one will be taken into account.
* Output a gif containing all of the result images :
```
$ pixelize [basic syntax] [gif] [reverse] [full]
```
* imageName = name of the image, in the current directory, to pixelize.
* X = Width of each group of pixels to fuse (Ex : 5 will fuse every group of 5\*5 pixels from the image)
* Y = Number of results, with increasing X at each result (Ex : 5 3 will print 3 results while fusing groups of 5\*5 pixels for the first result, 6\*6 for the second, etc)
* Z = Change to the step increase between each result (Ex : 5 3 5 will print 3 results while fusing groups of 5\*5 pixels for the first result, 10\*10 for the second, etc)

3. Clear the folder of the result files :
You can add the optional parameter "reverse" or "full" to change the gif animation.

The "reverse" parameter will reverse the animation.

The "full" parameter will add the reversed animation to the normal one and make a loop of them.

4. Clear the folder of the result files :
```
$ pixelize clear
```
4. Redo the last pixelization :
5. Redo the last pixelization :
```
$ pixelize redo
```
The "clear" and "redo" parameters can be used with the "log" or "verb" secondary arguments.


80 changes: 76 additions & 4 deletions main/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ import (
"strconv"
)

const (
NONE = iota
DEBUG = iota
INFO = iota
)

var LogLevel = NONE

func param(index int) int {
logIfVerbose(DEBUG, "param[ %v ]", index)
var nb int
var err error
if len(os.Args) < (index + 1) {
Expand All @@ -35,18 +44,81 @@ func hasParam(param string) bool {
return false
}

func printInTerminal(img image.Image, pointMin image.Point, pointMax image.Point, jump int) {
func printInTerminal(img image.Image, jump int, index int) {
logIfVerbose(DEBUG, "printInTerminal[ %v ]", jump)
bounds := img.Bounds()
changedImage := image.NewPaletted(bounds, palette.Plan9)
draw.Draw(changedImage, changedImage.Rect, img, bounds.Min, draw.Src)
printedText := "\n"
for y := pointMin.Y; y < pointMax.Y; y += jump {
for x := pointMin.X; x < pointMax.X; x += jump {
if hasParam("pixel") {
jump = 1
}
for y := bounds.Min.Y; y < bounds.Max.Y; y += jump {
for x := bounds.Min.X; x < bounds.Max.X; x += jump {
colorA := changedImage.ColorIndexAt(x, y)
printedText += "\033[48;5;" + strconv.Itoa(int(colorA)) + "m "
}
printedText += "\033[0;00m\n"
}
log.Print(printedText)
saveStr(printedText)
strSuffix := ""
if param(3) > 1 {
strSuffix = strconv.Itoa(index + 1)
}
saveStr(printedText, strSuffix)
}

func initLogLevel() {
if hasParam("log") {
LogLevel = INFO
}
if hasParam("verb") {
LogLevel = DEBUG
}
}

func logIfVerbose(level int, str string, obj ...interface{}) {
if LogLevel == DEBUG || (LogLevel == INFO && level == DEBUG) {
print(str, obj...)
}
}

func print(str string, obj ...interface{}) {
if len(obj) == 0 {
log.Print(str)
} else {
log.Printf(str, obj...)
}
}

func logIfExists(obj interface{}) {
if obj != nil {
log.Print(obj)
}
}

func printManual() {
logIfVerbose(DEBUG, "printManual")
log.Print("Basic syntax : " + os.Args[0] + " [imgName] [X] [Y] [Z] [...]")
log.Print("Alt. syntax : " + os.Args[0] + " [first-hand argument]")
log.Print("imgName : Name of the file.")
log.Print("X : Optional - Pixelization level.")
log.Print("Y : Optional - Number of results with increasing pixelization.")
log.Print("Z : Optional - Pixelization level increase between each result.")
log.Print("... : Optional - Secondary arguments in no particular order.")
log.Print("X, Y and Z will be 1 by default if not set.")
log.Print("-----------------------------------")
log.Print("First-hand arguments :")
log.Print("- 'man' or 'help' or nothing : Prints the manual.")
log.Print("- 'clear' : Removes every file generated by the program in the directory.")
log.Print("- 'redo' : Relaunches the command with the last parameters used with the program.")
log.Print("-----------------------------------")
log.Print("Secondary arguments :")
log.Print("- 'pixel' : Reduce the size of the image so each pixelized group of colors will display as a pixel.")
log.Print("- 'print' : Print each result in the terminal, and save a print.log file containing the color codes of the last result.")
log.Print("- 'gif' : Adds a gif file to the outputs, containing each result as a frame. Ignored if 'pixel' is used too.")
log.Print("- 'reverse' : Reverses the gif images' order.")
log.Print("- 'full' : Adds the reverted version to the original gif, instead of replacing the original.")
log.Print("- 'verb' : Log all operations of the program (heavy logging).")
log.Print("- 'log' : Lighter logging, focusing on the essential.")
}
78 changes: 45 additions & 33 deletions main/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import (
"image/draw"
"image/gif"
"image/png"
"log"
"os"
"strconv"
)

const GifDelayEachFrame = 20

func launchPixellisator(f *os.File, min int, count int, increase int) {
logIfVerbose(DEBUG, "launchPixellisator[ %v / %v / %v / %v ]", f.Name(), min, count, increase)
img, _, errImageDecode := image.Decode(f)
logIfExists(errImageDecode)
if errImageDecode != nil {
log.Print("Cannot decode image")
return
}
b := img.Bounds()
Expand All @@ -35,53 +35,61 @@ func launchPixellisator(f *os.File, min int, count int, increase int) {
if count > 1 {
name = "result" + strconv.Itoa(i+1) + ".png"
}
out, errOutput := os.Create(name)
if errOutput != nil {
log.Print("Cannot create image")
}
out, errOutput := os.Create(FileDirectory + name)
logIfExists(errOutput)
errOutputEncode := png.Encode(out, newImg)
if errOutputEncode != nil {
log.Print("Cannot encode image")
}
if hasParam("gif") {
logIfExists(errOutputEncode)
if hasParam("gif") && !hasParam("pixel") {
addToGif(&gifImg, newImg)
}
if hasParam("print") {
printInTerminal(newImg, pointMin, pointMax, min+(i*increase))
printInTerminal(newImg, min+(i*increase), i)
}
if i+1 == count {
if hasParam("gif") {
if hasParam("reverse") {
reverseGif(&gifImg)
}
if hasParam("full") {
addReverseToGif(&gifImg)
}
gifOutput, errGif := os.Create("results.gif")
if errGif != nil {
log.Print("Cannot create gif image")
}
errGifEncode := gif.EncodeAll(gifOutput, &gifImg)
if errGifEncode != nil {
log.Print("Cannot encode gif image")
}
if i+1 == count && hasParam("gif") && !hasParam("pixel") {
if hasParam("reverse") {
reverseGif(&gifImg)
}
if hasParam("full") {
addReverseToGif(&gifImg)
}
gifOutput, errGif := os.Create(FileDirectory + "results.gif")
logIfExists(errGif)
errGifEncode := gif.EncodeAll(gifOutput, &gifImg)
logIfExists(errGifEncode)
}
}
}

func repixellise(img image.Image, pointMin image.Point, pointMax image.Point, min int) image.Image {
result := image.NewRGBA(image.Rectangle{Min: pointMin, Max: pointMax})
for y := pointMin.Y; y < pointMax.Y; y += min {
for x := pointMin.X; x < pointMax.X; x += min {
colorRGBA := avg(img, x, y, min)
squareFill(result, x, y, colorRGBA, min)
func repixellise(img image.Image, pointMin image.Point, pointMax image.Point, pixelization int) image.Image {
logIfVerbose(DEBUG, "repixellise[ %v / %v / %v ]", pointMin, pointMax, pixelization)
i := 0
j := 0
var result *image.RGBA

if hasParam("pixel") {
newPointMax := image.Point{X: (pointMax.X / pixelization) + 1, Y: (pointMax.Y / pixelization) + 1}
result = image.NewRGBA(image.Rectangle{Min: pointMin, Max: newPointMax})
} else {
result = image.NewRGBA(image.Rectangle{Min: pointMin, Max: pointMax})
}
for y := pointMin.Y; y < pointMax.Y; y += pixelization {
for x := pointMin.X; x < pointMax.X; x += pixelization {
colorRGBA := avg(img, x, y, pixelization)
if hasParam("pixel") {
result.Set(i, j, colorRGBA)
} else {
squareFill(result, x, y, colorRGBA, pixelization)
}
i++
}
i = 0
j++
}
return result
}

func avg(img image.Image, x int, y int, count int) color.RGBA {
logIfVerbose(INFO, "avg[ { %v ; %v } / %v ]", x, y, count)
total := count * count

r := 0
Expand Down Expand Up @@ -114,6 +122,7 @@ func avg(img image.Image, x int, y int, count int) color.RGBA {
}

func squareFill(img *image.RGBA, x int, y int, rgba color.RGBA, min int) {
logIfVerbose(INFO, "squareFill[ { %v ; %v } / %v / %v ]", x, y, rgba, min)
for i := 0; i < min; i++ {
for j := 0; j < min; j++ {
img.Set(x+i, y+j, rgba)
Expand All @@ -122,20 +131,23 @@ func squareFill(img *image.RGBA, x int, y int, rgba color.RGBA, min int) {
}

func addToGif(gifImg *gif.GIF, img image.Image) {
logIfVerbose(DEBUG, "addToGif")
palettedImage := image.NewPaletted(img.Bounds(), palette.Plan9)
draw.Draw(palettedImage, palettedImage.Rect, img, img.Bounds().Min, draw.Src)
gifImg.Image = append(gifImg.Image, palettedImage)
gifImg.Delay = append(gifImg.Delay, GifDelayEachFrame)
}

func addReverseToGif(gifImg *gif.GIF) {
logIfVerbose(DEBUG, "addReverseToGif")
for i := len(gifImg.Image) - 2; i > 0; i-- {
gifImg.Image = append(gifImg.Image, gifImg.Image[i])
gifImg.Delay = append(gifImg.Delay, GifDelayEachFrame)
}
}

func reverseGif(gifImg *gif.GIF) {
logIfVerbose(DEBUG, "reverseGif")
var images []*image.Paletted
for i := len(gifImg.Image) - 1; i >= 0; i-- {
images = append(images, gifImg.Image[i])
Expand Down
45 changes: 31 additions & 14 deletions main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,58 @@ package main
import (
_ "image/jpeg"
_ "image/png"
"log"
"os"
)

var WorkingDirectory string
var FileDirectory string
var SaveDir string
var AppName = "pixelizer"

func main() {
if len(os.Args) < 2 || os.Args[1] == "man" || os.Args[1] == "help" {
log.Print("Use : " + os.Args[0] + " [1] [2] [3] [4]")
log.Print("1 : Name of the file")
log.Print("2 : Pixelization level")
log.Print("3 : Optional - Number of results with increasing pixelization")
log.Print("4 : Optional - Pixelization level increase between each result")
printManual()
return
}
initLogLevel()
mainParam := os.Args[1]

if mainParam == "clear" {
setSaveDir()
readAndGetParams()
setPreviousWorkingDirectory()
addWorkingDirToArgs()
setFileDirectory()
clearResults()
} else if mainParam == "redo" {
img, min, count, increase := readAndGetParams()
f, err := os.Open(img)
if err != nil {
log.Print("Cannot find this file.")
setSaveDir()
readAndGetParams()
setPreviousWorkingDirectory()
addWorkingDirToArgs()
setFileDirectory()
img := os.Args[1]
min := param(2)
count := param(3)
increase := param(4)
f, errOpenImg := os.Open(FileDirectory + getNameOfFile(img))
logIfExists(errOpenImg)
if errOpenImg != nil {
return
}
launchPixellisator(f, min, count, increase)
} else {
f, err := os.Open(mainParam)
if err != nil {
log.Print("Cannot find this file.")
setDirVariables()
os.Args = append(os.Args, WorkingDirectory)
f, errOpenImage := os.Open(mainParam)
logIfExists(errOpenImage)
if errOpenImage != nil {
return
}
defer f.Close()
min := param(2)
count := param(3)
increase := param(4)
launchPixellisator(f, min, count, increase)
save(min, count, increase)
save()
}
}
Loading

0 comments on commit 33effda

Please sign in to comment.