mirror of
https://github.com/gen2brain/cbconvert
synced 2025-10-13 18:18:52 +02:00
Remove levels
This commit is contained in:
40
README.md
40
README.md
@@ -64,8 +64,8 @@ This is what it looks like in the PCManFM file manager:
|
|||||||
Best fit for required width and height (default "false")
|
Best fit for required width and height (default "false")
|
||||||
--format
|
--format
|
||||||
Image format, valid values are jpeg, png, tiff, bmp, webp, avif, jxl (default "jpeg")
|
Image format, valid values are jpeg, png, tiff, bmp, webp, avif, jxl (default "jpeg")
|
||||||
--archive
|
--archive
|
||||||
Archive format, valid values are zip, tar (default "zip")
|
Archive format, valid values are zip, tar (default "zip")
|
||||||
--quality
|
--quality
|
||||||
Image quality (default "75")
|
Image quality (default "75")
|
||||||
--filter
|
--filter
|
||||||
@@ -77,7 +77,7 @@ This is what it looks like in the PCManFM file manager:
|
|||||||
--no-nonimage
|
--no-nonimage
|
||||||
Remove non-image files from the archive (default "false")
|
Remove non-image files from the archive (default "false")
|
||||||
--no-convert
|
--no-convert
|
||||||
Do not transform or convert images (default "false")
|
Do not transform or convert images (default "false")
|
||||||
--grayscale
|
--grayscale
|
||||||
Convert images to grayscale (monochromatic) (default "false")
|
Convert images to grayscale (monochromatic) (default "false")
|
||||||
--rotate
|
--rotate
|
||||||
@@ -88,16 +88,6 @@ This is what it looks like in the PCManFM file manager:
|
|||||||
Adjust the contrast of the images, must be in the range (-100, 100) (default "0")
|
Adjust the contrast of the images, must be in the range (-100, 100) (default "0")
|
||||||
--suffix
|
--suffix
|
||||||
Add suffix to file basename (default "")
|
Add suffix to file basename (default "")
|
||||||
--levels-inmin
|
|
||||||
Shadow input value (default "0")
|
|
||||||
--levels-gamma
|
|
||||||
Midpoint/Gamma (default "1")
|
|
||||||
--levels-inmax
|
|
||||||
Highlight input value (default "255")
|
|
||||||
--levels-outmin
|
|
||||||
Shadow output value (default "0")
|
|
||||||
--levels-outmax
|
|
||||||
Highlight output value (default "255")
|
|
||||||
--outdir
|
--outdir
|
||||||
Output directory (default ".")
|
Output directory (default ".")
|
||||||
--size
|
--size
|
||||||
@@ -153,19 +143,19 @@ This is what it looks like in the PCManFM file manager:
|
|||||||
--quiet
|
--quiet
|
||||||
Hide console output (default "false")
|
Hide console output (default "false")
|
||||||
|
|
||||||
meta
|
meta
|
||||||
CBZ metadata
|
CBZ metadata
|
||||||
|
|
||||||
--cover
|
--cover
|
||||||
Print cover name (default "false")
|
Print cover name (default "false")
|
||||||
--comment
|
--comment
|
||||||
Print zip comment (default "false")
|
Print zip comment (default "false")
|
||||||
--comment-body
|
--comment-body
|
||||||
Set zip comment (default "")
|
Set zip comment (default "")
|
||||||
--file-add
|
--file-add
|
||||||
Add file to archive (default "")
|
Add file to archive (default "")
|
||||||
--file-remove
|
--file-remove
|
||||||
Remove file(s) from archive (glob pattern, i.e. *.xml) (default "")
|
Remove file(s) from archive (glob pattern, i.e. *.xml) (default "")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
71
cbconvert.go
71
cbconvert.go
@@ -121,16 +121,6 @@ type Options struct {
|
|||||||
Size int
|
Size int
|
||||||
// Hide console output
|
// Hide console output
|
||||||
Quiet bool
|
Quiet bool
|
||||||
// Shadow input value
|
|
||||||
LevelsInMin int
|
|
||||||
// Highlight input value
|
|
||||||
LevelsInMax int
|
|
||||||
// Midpoint/gamma
|
|
||||||
LevelsGamma float64
|
|
||||||
// Shadow output value
|
|
||||||
LevelsOutMin int
|
|
||||||
// Highlight output value
|
|
||||||
LevelsOutMax int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converter type.
|
// Converter type.
|
||||||
@@ -180,9 +170,6 @@ func NewOptions() Options {
|
|||||||
o.Archive = "zip"
|
o.Archive = "zip"
|
||||||
o.Quality = 75
|
o.Quality = 75
|
||||||
o.Filter = 2
|
o.Filter = 2
|
||||||
o.LevelsGamma = 1.0
|
|
||||||
o.LevelsInMax = 255
|
|
||||||
o.LevelsOutMax = 255
|
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
@@ -487,14 +474,6 @@ func (c *Converter) imageConvert(ctx context.Context, img image.Image, index int
|
|||||||
|
|
||||||
img = c.imageTransform(img)
|
img = c.imageTransform(img)
|
||||||
|
|
||||||
if c.Opts.LevelsInMin != 0 || c.Opts.LevelsInMax != 255 || c.Opts.LevelsGamma != 1.0 ||
|
|
||||||
c.Opts.LevelsOutMin != 0 || c.Opts.LevelsOutMax != 255 {
|
|
||||||
img, err = c.imageLevel(img)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("imageConvert: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := os.Create(fileName)
|
w, err := os.Create(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("imageConvert: %w", err)
|
return fmt.Errorf("imageConvert: %w", err)
|
||||||
@@ -553,48 +532,6 @@ func (c *Converter) imageTransform(img image.Image) image.Image {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// imageLevel applies a Photoshop-like levels operation on an image.
|
|
||||||
func (c *Converter) imageLevel(img image.Image) (image.Image, error) {
|
|
||||||
mw := imagick.NewMagickWand()
|
|
||||||
defer mw.Destroy()
|
|
||||||
|
|
||||||
rgba := imageToRGBA(img)
|
|
||||||
err := mw.ConstituteImage(uint(img.Bounds().Dx()), uint(img.Bounds().Dy()), "RGBA", imagick.PIXEL_CHAR, rgba.Pix)
|
|
||||||
if err != nil {
|
|
||||||
return img, fmt.Errorf("imageLevel: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, qrange := imagick.GetQuantumRange()
|
|
||||||
quantumRange := float64(qrange)
|
|
||||||
|
|
||||||
inMin := (quantumRange * float64(c.Opts.LevelsInMin)) / 255
|
|
||||||
inMax := (quantumRange * float64(c.Opts.LevelsInMax)) / 255
|
|
||||||
outMin := (quantumRange * float64(c.Opts.LevelsOutMin)) / 255
|
|
||||||
outMax := (quantumRange * float64(c.Opts.LevelsOutMax)) / 255
|
|
||||||
|
|
||||||
if err := mw.LevelImage(inMin, c.Opts.LevelsGamma, inMax); err != nil {
|
|
||||||
return img, fmt.Errorf("imageLevel: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mw.LevelImage(-outMin, 1.0, quantumRange+(quantumRange-outMax)); err != nil {
|
|
||||||
return img, fmt.Errorf("imageLevel: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
blob := mw.GetImageBlob()
|
|
||||||
|
|
||||||
var i image.Image
|
|
||||||
i, err = c.imageDecode(bytes.NewReader(blob))
|
|
||||||
if err != nil {
|
|
||||||
e := err
|
|
||||||
i, err = c.imDecode(bytes.NewReader(blob), "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("imageLevel: %w: %w", e, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// imageDecode decodes image from reader.
|
// imageDecode decodes image from reader.
|
||||||
func (c *Converter) imageDecode(reader io.Reader) (image.Image, error) {
|
func (c *Converter) imageDecode(reader io.Reader) (image.Image, error) {
|
||||||
img, _, err := image.Decode(reader)
|
img, _, err := image.Decode(reader)
|
||||||
@@ -1225,14 +1162,6 @@ func (c *Converter) Preview(fileName string, fileInfo os.FileInfo, width, height
|
|||||||
|
|
||||||
i = c.imageTransform(i)
|
i = c.imageTransform(i)
|
||||||
|
|
||||||
if c.Opts.LevelsInMin != 0 || c.Opts.LevelsInMax != 255 || c.Opts.LevelsGamma != 1.0 ||
|
|
||||||
c.Opts.LevelsOutMin != 0 || c.Opts.LevelsOutMax != 255 {
|
|
||||||
i, err = c.imageLevel(i)
|
|
||||||
if err != nil {
|
|
||||||
return img, fmt.Errorf("%s: %w", fileName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var w bytes.Buffer
|
var w bytes.Buffer
|
||||||
|
|
||||||
switch c.Opts.Format {
|
switch c.Opts.Format {
|
||||||
|
@@ -120,11 +120,6 @@ func options() cbconvert.Options {
|
|||||||
opts.Brightness = iup.GetHandle("Brightness").GetInt("VALUE")
|
opts.Brightness = iup.GetHandle("Brightness").GetInt("VALUE")
|
||||||
opts.Contrast = iup.GetHandle("Contrast").GetInt("VALUE")
|
opts.Contrast = iup.GetHandle("Contrast").GetInt("VALUE")
|
||||||
opts.Rotate = iup.GetHandle("Rotate").GetInt("VALUESTRING")
|
opts.Rotate = iup.GetHandle("Rotate").GetInt("VALUESTRING")
|
||||||
opts.LevelsInMin = iup.GetHandle("LevelsInMin").GetInt("VALUE")
|
|
||||||
opts.LevelsInMax = iup.GetHandle("LevelsInMax").GetInt("VALUE")
|
|
||||||
opts.LevelsOutMin = iup.GetHandle("LevelsOutMin").GetInt("VALUE")
|
|
||||||
opts.LevelsOutMax = iup.GetHandle("LevelsOutMax").GetInt("VALUE")
|
|
||||||
opts.LevelsGamma = iup.GetHandle("LevelsGamma").GetDouble("VALUE")
|
|
||||||
|
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
@@ -539,94 +534,6 @@ func tabs() iup.Ihandle {
|
|||||||
return iup.DEFAULT
|
return iup.DEFAULT
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
iup.Vbox(
|
|
||||||
iup.Label("Input Levels:"),
|
|
||||||
iup.Hbox(
|
|
||||||
iup.Text().SetAttributes(`SPIN=YES, SPINMAX=255, VALUE=0, VISIBLECOLUMNS=3, MASK="/d*"`).
|
|
||||||
SetHandle("LevelsInMin").SetAttribute("TIP", "Min").
|
|
||||||
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
|
|
||||||
ih.SetAttribute("MYVALUE", ih.GetInt("VALUE"))
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})).
|
|
||||||
SetCallback("KILLFOCUS_CB", iup.KillFocusFunc(func(ih iup.Ihandle) int {
|
|
||||||
if ih.GetAttribute("MYVALUE") != "" {
|
|
||||||
previewPost()
|
|
||||||
}
|
|
||||||
ih.SetAttribute("MYVALUE", "")
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})),
|
|
||||||
iup.Fill(),
|
|
||||||
iup.Val("").SetAttributes(`VALUE=1.0, SHOWTICKS=10`).
|
|
||||||
SetHandle("LevelsGamma").SetAttribute("TIP", "Gamma").
|
|
||||||
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
|
|
||||||
ih.SetAttribute("MYVALUE", ih.GetInt("VALUE"))
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})).
|
|
||||||
SetCallback("KILLFOCUS_CB", iup.KillFocusFunc(func(ih iup.Ihandle) int {
|
|
||||||
if ih.GetAttribute("MYVALUE") != "" {
|
|
||||||
previewPost()
|
|
||||||
}
|
|
||||||
ih.SetAttribute("MYVALUE", "")
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})),
|
|
||||||
iup.Fill(),
|
|
||||||
iup.Text().SetAttributes(`SPIN=YES, SPINMAX=255, VALUE=255, VISIBLECOLUMNS=3, MASK="/d*"`).
|
|
||||||
SetHandle("LevelsInMax").SetAttribute("TIP", "Max").
|
|
||||||
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
|
|
||||||
ih.SetAttribute("MYVALUE", ih.GetInt("VALUE"))
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})).
|
|
||||||
SetCallback("KILLFOCUS_CB", iup.KillFocusFunc(func(ih iup.Ihandle) int {
|
|
||||||
if ih.GetAttribute("MYVALUE") != "" {
|
|
||||||
previewPost()
|
|
||||||
}
|
|
||||||
ih.SetAttribute("MYVALUE", "")
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})),
|
|
||||||
).SetAttributes("ALIGNMENT=ACENTER, MAXSIZE=340x"),
|
|
||||||
),
|
|
||||||
iup.Vbox(
|
|
||||||
iup.Label("Output Levels:"),
|
|
||||||
iup.Hbox(
|
|
||||||
iup.Text().SetAttributes(`SPIN=YES, SPINMAX=255, VALUE=0, VISIBLECOLUMNS=3, MASK="/d*"`).
|
|
||||||
SetHandle("LevelsOutMin").SetAttribute("TIP", "Min").
|
|
||||||
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
|
|
||||||
ih.SetAttribute("MYVALUE", ih.GetInt("VALUE"))
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})).
|
|
||||||
SetCallback("KILLFOCUS_CB", iup.KillFocusFunc(func(ih iup.Ihandle) int {
|
|
||||||
if ih.GetAttribute("MYVALUE") != "" {
|
|
||||||
previewPost()
|
|
||||||
}
|
|
||||||
ih.SetAttribute("MYVALUE", "")
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})),
|
|
||||||
iup.Fill(),
|
|
||||||
iup.Text().SetAttributes(`SPIN=YES, SPINMAX=255, VALUE=255, VISIBLECOLUMNS=3, MASK="/d*"`).
|
|
||||||
SetHandle("LevelsOutMax").SetAttribute("TIP", "Max").
|
|
||||||
SetCallback("VALUECHANGED_CB", iup.ValueChangedFunc(func(ih iup.Ihandle) int {
|
|
||||||
ih.SetAttribute("MYVALUE", ih.GetInt("VALUE"))
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})).
|
|
||||||
SetCallback("KILLFOCUS_CB", iup.KillFocusFunc(func(ih iup.Ihandle) int {
|
|
||||||
if ih.GetAttribute("MYVALUE") != "" {
|
|
||||||
previewPost()
|
|
||||||
}
|
|
||||||
ih.SetAttribute("MYVALUE", "")
|
|
||||||
|
|
||||||
return iup.DEFAULT
|
|
||||||
})),
|
|
||||||
).SetAttributes("ALIGNMENT=ACENTER, MAXSIZE=340x"),
|
|
||||||
),
|
|
||||||
).SetHandle("VboxTransform").SetAttributes("MARGIN=5x5, GAP=5")
|
).SetHandle("VboxTransform").SetAttributes("MARGIN=5x5, GAP=5")
|
||||||
|
|
||||||
return iup.Tabs(
|
return iup.Tabs(
|
||||||
|
@@ -181,11 +181,6 @@ func parseFlags() (cbconvert.Options, []string) {
|
|||||||
convert.IntVar(&opts.Brightness, "brightness", 0, "Adjust the brightness of the images, must be in the range (-100, 100)")
|
convert.IntVar(&opts.Brightness, "brightness", 0, "Adjust the brightness of the images, must be in the range (-100, 100)")
|
||||||
convert.IntVar(&opts.Contrast, "contrast", 0, "Adjust the contrast of the images, must be in the range (-100, 100)")
|
convert.IntVar(&opts.Contrast, "contrast", 0, "Adjust the contrast of the images, must be in the range (-100, 100)")
|
||||||
convert.StringVar(&opts.Suffix, "suffix", "", "Add suffix to file basename")
|
convert.StringVar(&opts.Suffix, "suffix", "", "Add suffix to file basename")
|
||||||
convert.IntVar(&opts.LevelsInMin, "levels-inmin", 0, "Shadow input value")
|
|
||||||
convert.Float64Var(&opts.LevelsGamma, "levels-gamma", 1.0, "Midpoint/Gamma")
|
|
||||||
convert.IntVar(&opts.LevelsInMax, "levels-inmax", 255, "Highlight input value")
|
|
||||||
convert.IntVar(&opts.LevelsOutMin, "levels-outmin", 0, "Shadow output value")
|
|
||||||
convert.IntVar(&opts.LevelsOutMax, "levels-outmax", 255, "Highlight output value")
|
|
||||||
convert.StringVar(&opts.OutDir, "outdir", ".", "Output directory")
|
convert.StringVar(&opts.OutDir, "outdir", ".", "Output directory")
|
||||||
convert.IntVar(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
|
convert.IntVar(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
|
||||||
convert.BoolVar(&opts.Recursive, "recursive", false, "Process subdirectories recursively")
|
convert.BoolVar(&opts.Recursive, "recursive", false, "Process subdirectories recursively")
|
||||||
|
Reference in New Issue
Block a user