42 Commits

Author SHA1 Message Date
crouvpony47
bbc34345a1 output redirection and color calculation fixes; minor improvements
fix: no longer accessing unexisting element of color_per_count;
fix: improved redirection handing;
fix: don't print empty rows in thumbs mode.
2019-05-22 11:11:39 +02:00
Stefan Haustein
53dff6f5b9 Update README.md 2019-03-26 21:35:23 +01:00
Stefan Haustein
12089c098a Update README.md 2019-03-26 21:32:58 +01:00
Stefan Haustein
1cdfc4d9db Update README.md 2019-03-26 21:30:28 +01:00
cabelo
128e106b82 Redirect STDOUT to file 2019-03-26 21:26:43 +01:00
cabelo
5ef1f70a3a Redirect STDOUT to file 2019-03-26 21:26:43 +01:00
Stefan Haustein
f055e5b675 Revert "Persistence options"
This reverts commit aef2fbccdc.
2019-03-23 22:33:28 +01:00
Stefan Haustein
d749d51042 Revert "Constant standard output stream"
This reverts commit 543cebef37.
2019-03-23 22:33:28 +01:00
Stefan Haustein
cd2805d33d Revert "null values"
This reverts commit 9717adc840.
2019-03-23 22:33:28 +01:00
Stefan Haustein
7e5b9d94ee Revert "null values"
This reverts commit 28e9f5e40e.
2019-03-23 22:33:28 +01:00
Stefan Haustein
0973fbd76c Revert "null values"
This reverts commit 3e57ebb80c.
2019-03-23 22:33:28 +01:00
Alan De Smet
419056506f Cleanup to match upstream style. 2019-03-23 22:32:20 +01:00
Alan De Smet
f97c6e9eb0 Make operator* a member of struct size
instead of being global
2019-03-23 22:32:20 +01:00
Alan De Smet
06467c38d8 Center tall, skinny thumbnails in their space. 2019-03-23 22:32:20 +01:00
Alan De Smet
6b80bc0717 Preserve aspect ratio of tall, skinny images in thumbnails. 2019-03-23 22:32:20 +01:00
Alan De Smet
69f57a4730 Add operator<<(istream) for size for debugging 2019-03-23 22:32:20 +01:00
Alan De Smet
b58820e647 Extract size-to-fit logic for re-use in thumbnails. 2019-03-23 22:32:20 +01:00
cabelo
3e57ebb80c null values 2019-03-23 22:30:54 +01:00
cabelo
28e9f5e40e null values 2019-03-23 22:30:54 +01:00
cabelo
9717adc840 null values 2019-03-23 22:30:54 +01:00
cabelo
543cebef37 Constant standard output stream 2019-03-23 22:30:54 +01:00
cabelo
aef2fbccdc Persistence options 2019-03-23 22:30:54 +01:00
Thomas Kupper
9734ff585d Extend Makefile for cross-compiling 2019-03-23 19:59:39 +01:00
Alan De Smet
9943deed2c Convert greyscale inputs to RGB. 2019-03-22 20:57:58 +01:00
CHEN Feng
287fde3341 Fix the '-Wcatch-value' warning under gcc 7.3.0
tiv.cpp:464:45: warning: catching polymorphic type ‘struct cimg_library::CImgIOException’ by value [-Wcatch-value=]
2019-03-11 20:52:08 +01:00
Stefan Haustein
949f72ffa9 Update README.md 2019-03-04 20:11:59 +01:00
Stefan Haustein
f80071243f Update README.md 2019-01-31 22:39:55 +01:00
Stefan Haustein
34dd22e1e8 Update README.md 2019-01-14 21:08:40 +01:00
Stefan Haustein
b27e359e4f Update README.md 2019-01-14 21:07:33 +01:00
stefan.haustein@gmail.com
cca06fdaca Snapcraft :) 2019-01-13 22:47:16 +01:00
teresaejunior
deab25bf68 Include Snap build instructions 2018-12-21 12:22:35 +01:00
teresaejunior
37ceba3e0b Reflect the new snapcraft.yaml 2018-12-21 12:22:35 +01:00
teresaejunior
ed158d6ba9 Include snapcraft temporary files 2018-12-21 12:22:35 +01:00
teresaejunior
dd92c03299 Fix Snap build 2018-12-21 12:22:35 +01:00
Stefan Haustein
073b76d9b4 Update README.md 2018-12-14 20:13:01 +01:00
Stefan Haustein
141205e83e Update README.md 2018-12-14 20:12:28 +01:00
Stefan Haustein
4a1a82a5c0 Update README.md 2018-12-14 20:12:15 +01:00
Stefan Haustein
b66e502782 Update README.md 2018-12-14 20:10:58 +01:00
Stefan Haustein
40cd46ea4e Update README.md 2018-12-14 20:10:18 +01:00
stefan.haustein@gmail.com
945502ff76 slightly improved snapcraft.yaml 2018-12-09 19:36:48 +01:00
stefan.haustein@gmail.com
4b116332f7 Merge branch 'master' of https://github.com/stefanhaustein/TerminalImageViewer 2018-12-09 19:30:18 +01:00
stefan.haustein@gmail.com
c7c05bba79 check in non-working snapcraft.yaml as a strating point for dev. 2018-12-09 19:29:46 +01:00
5 changed files with 190 additions and 26 deletions

15
.gitignore vendored
View File

@@ -91,4 +91,17 @@ Icon
.AppleDesktop .AppleDesktop
Network Trash Folder Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
# Intellij
.idea/
*.iml
###Snap###
parts/
prime/
snap/
stage/
*.snap

View File

@@ -13,14 +13,27 @@ For each 4x8 pixel cell of the (potentially downscaled) image:
See the difference by disabling this optimization using the `-0` option. Or just take a look at the comparison image at the end of this text. See the difference by disabling this optimization using the `-0` option. Or just take a look at the comparison image at the end of this text.
## News
- 2019-03-26: Exciting week: @Cableo has fixed output redirection, @boretom has added cross-compilation support to the build file and @AlanDeSmet has fixed tall thumbnails and greyscale images.
- 2019-01-14: Install via snap: `sudo snap install --edge tiv`
## Installation ## Installation
### Snap
sudo snap install --edge tiv
### Build from source
sudo apt install imagemagick || yum install ImageMagick sudo apt install imagemagick || yum install ImageMagick
git clone https://github.com/stefanhaustein/TerminalImageViewer.git git clone https://github.com/stefanhaustein/TerminalImageViewer.git
cd TerminalImageViewer/src/main/cpp cd TerminalImageViewer/src/main/cpp
make make
sudo make install sudo make install
Note: On MacOS, you'll need to install GCC because of this issue: https://stackoverflow.com/q/42633477. Find some more details here: https://github.com/stefanhaustein/TerminalImageViewer/issues/36
## Usage ## Usage
tiv [options] <filename(s)> tiv [options] <filename(s)>
@@ -33,11 +46,14 @@ The shell will expand wildcards. By default, thumbnails and file names will be d
https://build.opensuse.org/package/show/home:megamaced/terminalimageviewer https://build.opensuse.org/package/show/home:megamaced/terminalimageviewer
- bperel has created a Docker image: - bperel has created a Docker image:
https://hub.docker.com/r/bperel/terminalimageviewer https://hub.docker.com/r/bperel/terminalimageviewer
- teresaejunior has created a snapcraft.yaml file, which can build a Snap package with `sudo docker run -it --rm -v "$PWD:$PWD" -w "$PWD" snapcore/snapcraft sh -c 'apt-get update && snapcraft'`, and then installed with `sudo snap install --dangerous ./*.snap`.
## Common problems ## Common problems
- If you see strange horizontal lines, the characters don't fully fill the character cell. Remove additional line spacing in your terminal app - If you see strange horizontal lines, the characters don't fully fill the character cell. Remove additional line spacing in your terminal app
- Wrong colors? Try -256 to use a 256 color palette instead of 24 bit colors - Wrong colors? Try -256 to use a 256 color palette instead of 24 bit colors
- Strange characters? Try -0 or install an use full unicode font (e.g. inconsolata or firacode)
## Examples ## Examples

73
snapcraft.yaml Normal file
View File

@@ -0,0 +1,73 @@
name: tiv
version: "v1.0.0"
summary: Terminal Image Viewer
description: |
tiv is a small C++ program to display images in a (modern) terminal using
RGB ANSI codes and unicode block graphic characters.
apps:
tiv:
command: usr/bin/tiv
plugs: [home]
parts:
tiv:
plugin: make
source-type: tar
source: https://github.com/stefanhaustein/TerminalImageViewer/archive/v1.0.0.tar.gz
source-subdir: src/main/cpp
build-packages:
- g++
- make
- imagemagick
override-build: |
snapcraftctl build
mkdir -p $SNAPCRAFT_PART_INSTALL/usr/bin/
install $SNAPCRAFT_PART_BUILD/tiv $SNAPCRAFT_PART_INSTALL/usr/bin/
imagemagick:
plugin: autotools
source: https://www.imagemagick.org/download/releases/ImageMagick-7.0.8-23.tar.xz
source-type: tar
configflags:
- --enable-hdri=yes
- --enable-shared=yes
- --enable-static=yes
- --with-autotrace=yes
- --with-fpx=no
- --with-gnu-ld=yes
- --with-gslib=yes
- --with-modules=no
- --with-quantum-depth=32
- --with-rsvg=yes
build-packages:
- autoconf
- build-essential
- fftw-dev
- libautotrace-dev
- libbz2-dev
- libdjvulibre-dev
- libfftw3-dev
- libfontconfig1-dev
- libfreetype6-dev
- libgs-dev
- libgvc6
- libjbig-dev
- libjpeg-dev
- liblcms2-dev
- liblqr-1-0-dev
- libltdl-dev
- libmagick++-dev
- libopenexr-dev
- libopenjp2-7-dev
- libpango1.0-dev
- libperl-dev
- libpng12-dev
- librsvg2-dev
- libtiff5-dev
- libwebp-dev
- libwmf-dev
- libx11-dev
- lzma-dev
- ocl-icd-opencl-dev
- perlmagick
- zlib1g-dev

View File

@@ -1,15 +1,22 @@
CXX=g++ # set CXX to g++ if not set
CXX ?= g++
default: tiv # append necessary arguments
override CPPFLAGS += -std=c++17 -Wall -fpermissive -fexceptions -O2
override LDFLAGS += -lstdc++fs -pthread -s
all: tiv
tiv.o: tiv.cpp CImg.h tiv.o: tiv.cpp CImg.h
$(CXX) -std=c++17 -Wall -fpermissive -fexceptions -O2 -c tiv.cpp -o tiv.o $(CXX) $(CPPFLAGS) -c tiv.cpp -o $@
tiv : tiv.o tiv : tiv.o
$(CXX) tiv.o -o tiv -lstdc++fs -pthread -s $(CXX) $^ -o $@ $(LDFLAGS)
install: tiv .PHONY: all install clean
cp tiv /usr/local/bin/tiv install: all
test -d $(DESTDIR)/usr/local/bin || mkdir -p $(DESTDIR)/usr/local/bin
cp tiv $(DESTDIR)/usr/local/bin/tiv
clean: clean:
rm -f tiv tiv.o rm -f tiv tiv.o

View File

@@ -195,8 +195,7 @@ CharData getCharData(const cimg_library::CImg<unsigned char> & image, int x0, in
int count2 = iter->first; int count2 = iter->first;
long max_count_color_1 = iter->second; long max_count_color_1 = iter->second;
long max_count_color_2 = max_count_color_1; long max_count_color_2 = max_count_color_1;
if (iter != color_per_count.rend()) { if ((++iter) != color_per_count.rend()) {
++iter;
count2 += iter->first; count2 += iter->first;
max_count_color_2 = iter->second; max_count_color_2 = iter->second;
} }
@@ -330,7 +329,7 @@ void emit_color(int flags, int r, int g, int b) {
int gq = COLOR_STEPS[gi]; int gq = COLOR_STEPS[gi];
int bq = COLOR_STEPS[bi]; int bq = COLOR_STEPS[bi];
int gray = std::round(r * 0.2989f + g * 0.5870f + b * 0.1140f); int gray = static_cast<int>(std::round(r * 0.2989f + g * 0.5870f + b * 0.1140f));
int gri = best_index(gray, GRAYSCALE_STEPS, GRAYSCALE_STEP_COUNT); int gri = best_index(gray, GRAYSCALE_STEPS, GRAYSCALE_STEP_COUNT);
int grq = GRAYSCALE_STEPS[gri]; int grq = GRAYSCALE_STEPS[gri];
@@ -382,6 +381,31 @@ void emit_image(const cimg_library::CImg<unsigned char> & image, int flags) {
} }
struct size {
size(unsigned int in_width, unsigned int in_height) :
width(in_width), height(in_height) {
}
size(cimg_library::CImg<unsigned int> img) :
width(img.width()), height(img.height()) {
}
unsigned int width;
unsigned int height;
size scaled(double scale) {
return size(width*scale, height*scale);
}
size fitted_within(size container) {
double scale = std::min(container.width / (double) width, container.height / (double) height);
return scaled(scale);
}
};
std::ostream& operator<<(std::ostream& stream, size sz) {
stream << sz.width << "x" << sz.height;
return stream;
}
void emit_usage() { void emit_usage() {
std::cerr << "Terminal Image Viewer" << std::endl << std::endl; std::cerr << "Terminal Image Viewer" << std::endl << std::endl;
std::cerr << "usage: tiv [options] <image> [<image>...]" << std::endl << std::endl; std::cerr << "usage: tiv [options] <image> [<image>...]" << std::endl << std::endl;
@@ -397,12 +421,42 @@ void emit_usage() {
enum Mode {AUTO, THUMBNAILS, FULL_SIZE}; enum Mode {AUTO, THUMBNAILS, FULL_SIZE};
/* Wrapper around CImg<T>(const char*) to ensure the result has 3 channels as RGB
*/
cimg_library::CImg<unsigned char> load_rgb_CImg(const char * const filename) {
cimg_library::CImg<unsigned char> image(filename);
if(image.spectrum() == 1) {
// Greyscale. Just copy greyscale data to all channels
cimg_library::CImg<unsigned char> rgb_image(image.width(), image.height(), image.depth(), 3);
for(unsigned int chn = 0; chn < 3; chn++) {
rgb_image.draw_image(0, 0, 0,chn, image);
}
return rgb_image;
}
return image;
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int maxWidth = 80;
int maxHeight = 24;
bool sizeDetectionSuccessful = true;
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); int ioStatus = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
// If redirecting STDOUT to one file ( col or row == 0, or the previous ioctl call's failed )
int maxWidth = w.ws_col * 4; if (ioStatus != 0 || (w.ws_col | w.ws_row) == 0) {
int maxHeight = w.ws_row * 8; ioStatus = ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
if (ioStatus != 0 || (w.ws_col | w.ws_row) == 0) {
std::cerr << "Warning: failed to determine most reasonable size, defaulting to 80x24" << std::endl;
sizeDetectionSuccessful = false;
}
}
if (sizeDetectionSuccessful)
{
maxWidth = w.ws_col * 4;
maxHeight = w.ws_row * 8;
}
int flags = 0; int flags = 0;
Mode mode = AUTO; Mode mode = AUTO;
int columns = 3; int columns = 3;
@@ -452,14 +506,14 @@ int main(int argc, char* argv[]) {
if (mode == FULL_SIZE || (mode == AUTO && file_names.size() == 1)) { if (mode == FULL_SIZE || (mode == AUTO && file_names.size() == 1)) {
for (unsigned int i = 0; i < file_names.size(); i++) { for (unsigned int i = 0; i < file_names.size(); i++) {
try { try {
cimg_library::CImg<unsigned char> image(file_names[i].c_str()); cimg_library::CImg<unsigned char> image = load_rgb_CImg(file_names[i].c_str());
if (image.width() > maxWidth || image.height() > maxHeight) { if (image.width() > maxWidth || image.height() > maxHeight) {
double scale = std::min(maxWidth / (double) image.width(), maxHeight / (double) image.height()); size new_size = size(image).fitted_within(size(maxWidth,maxHeight));
image.resize((int) (image.width() * scale), (int) (image.height() * scale), -100, -100, 5); image.resize(new_size.width, new_size.height, -100, -100, 5);
} }
emit_image(image, flags); emit_image(image, flags);
} catch(cimg_library::CImgIOException e) { } catch(cimg_library::CImgIOException & e) {
error = 1; error = 1;
std::cerr << "File format is not recognized for '" << file_names[i] << "'" << std::endl; std::cerr << "File format is not recognized for '" << file_names[i] << "'" << std::endl;
} }
@@ -471,6 +525,7 @@ int main(int argc, char* argv[]) {
int cw = (((maxWidth / 4) - 2 * (columns - 1)) / columns); int cw = (((maxWidth / 4) - 2 * (columns - 1)) / columns);
int tw = cw * 4; int tw = cw * 4;
cimg_library::CImg<unsigned char> image(tw * columns + 2 * 4 * (columns - 1), tw, 1, 3); cimg_library::CImg<unsigned char> image(tw * columns + 2 * 4 * (columns - 1), tw, 1, 3);
size maxThumbSize(tw, tw);
while (index < file_names.size()) { while (index < file_names.size()) {
image.fill(0); image.fill(0);
@@ -479,21 +534,21 @@ int main(int argc, char* argv[]) {
while (index < file_names.size() && count < columns) { while (index < file_names.size() && count < columns) {
std::string name = file_names[index++]; std::string name = file_names[index++];
try { try {
cimg_library::CImg<unsigned char> original(name.c_str()); cimg_library::CImg<unsigned char> original = load_rgb_CImg(name.c_str());
unsigned int cut = name.find_last_of("/"); auto cut = name.find_last_of("/");
sb += cut == std::string::npos ? name : name.substr(cut + 1); sb += cut == std::string::npos ? name : name.substr(cut + 1);
int th = original.height() * tw / original.width(); size newSize = size(original).fitted_within(maxThumbSize);
original.resize(tw, th, 1, -100, 5); original.resize(newSize.width, newSize.height, 1, -100, 5);
image.draw_image(count * (tw + 8), (tw - th) / 2, 0, 0, original); image.draw_image(count * (tw + 8) + (tw - newSize.width) / 2, (tw - newSize.height) / 2, 0, 0, original);
count++; count++;
unsigned int sl = count * (cw + 2); unsigned int sl = count * (cw + 2);
sb.resize(sl - 2, ' '); sb.resize(sl - 2, ' ');
sb += " "; sb += " ";
} catch (std::exception e) { } catch (std::exception & e) {
// Probably no image; ignore. // Probably no image; ignore.
} }
} }
emit_image(image, flags); if (count) emit_image(image, flags);
std::cout << sb << std::endl << std::endl; std::cout << sb << std::endl << std::endl;
} }
} }