Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ libhiptext_a_SOURCES = \
src/hiptext/jpeg.h \
src/hiptext/macterm.h \
src/hiptext/movie.h \
src/hiptext/x11.h \
src/hiptext/input.h \
src/hiptext/pixel.h \
src/hiptext/png.h \
src/hiptext/sixelprinter.h \
Expand All @@ -42,6 +44,8 @@ libhiptext_a_SOURCES = \
src/jpeg.cc \
src/macterm.cc \
src/movie.cc \
src/x11.cc \
src/input.cc \
src/pixel.cc \
src/pixel_parse.cc \
src/pixel_parse.rl \
Expand Down Expand Up @@ -72,6 +76,7 @@ hiptext_CPPFLAGS = $(libhiptext_a_CPPFLAGS)
hiptext_LDADD = \
libhiptext.a \
-ljpeg \
-lX11 \
$(LIBAVCODEC_LIBS) \
$(LIBAVFORMAT_LIBS) \
$(LIBAVUTIL_LIBS) \
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ AC_CHECK_LIB(jpeg, jpeg_set_defaults, [], [
AC_MSG_ERROR([error: libjpeg is required])
])

AC_PATH_XTRA

PKG_CHECK_MODULES(LIBAVCODEC, libavcodec)
PKG_CHECK_MODULES(LIBAVFORMAT, libavformat)
PKG_CHECK_MODULES(LIBAVUTIL, libavutil)
Expand Down
42 changes: 42 additions & 0 deletions src/artiste.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <glog/logging.h>

#include "hiptext/movie.h"
#include "hiptext/x11.h"

#ifdef __APPLE__
using sighandler_t = sig_t;
Expand All @@ -39,6 +40,12 @@ static void OnCtrlC(int /*signal*/) {
g_done = true;
}

static void SleepFPS(int fps) {
int ms = 1000 / fps;
timespec req = {ms / 1000, ms % 1000 * 1000000};
nanosleep(&req, nullptr);
}

inline double RatioOf(int width, int height) {
return static_cast<double>(width) / static_cast<double>(height);
}
Expand Down Expand Up @@ -187,6 +194,37 @@ void Artiste::PrintMovie(Movie movie) {
ShowCursor();
}

void Artiste::PrintX11(X11 x11) {
x11.InitializeMain();
ComputeDimensions(RatioOf(x11.grab_width, x11.grab_height));
x11.TermUpdate(width_, height_);
HideCursor();
ClearScreen();
sighandler_t old_handler = signal(SIGINT, OnCtrlC);
for (auto graphic : x11) {
if (g_done) {
break;
}
ResetCursor();
if (FLAGS_equalize) {
graphic.Equalize();
}
algorithm_(output_, graphic.BilinearScale(width_, height_));
if (x11.HandleInput()){
ComputeDimensions(RatioOf(x11.grab_width, x11.grab_height));
x11.TermUpdate(width_, height_);
}
SleepFPS(25);
if (FLAGS_stepthrough) {
string lulz;
std::getline(std::cin, lulz);
}
}
signal(SIGINT, old_handler);
x11.DestroyImage();
ShowCursor();
}

void Artiste::GenerateSpectrum() {
int width = term_width_;
int height = term_height_ * 2 - 2;
Expand Down Expand Up @@ -251,6 +289,10 @@ void Artiste::ResetCursor() {
output_ << "\x1b[H"; // ANSI put cursor in top left.
}

void Artiste::ClearScreen() {
output_ << "\x1b[2J"; // ANSI clear screen to background colour.
}

// For Emacs:
// Local Variables:
// mode:c++
Expand Down
34 changes: 25 additions & 9 deletions src/hiptext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "hiptext/png.h"
#include "hiptext/macterm.h"
#include "hiptext/movie.h"
#include "hiptext/x11.h"
#include "hiptext/xterm256.h"
#include "hiptext/termprinter.h"
#include "hiptext/sixelprinter.h"
Expand All @@ -45,10 +46,12 @@ DEFINE_string(bg, "black", "The native background of your terminal specified "
"you plan copy/pasting the output into something with a white "
"background like if you were spamming Reddit");
DEFINE_bool(bgprint, false, "Enable explicit styling when printing characters "
"that are nearly identical to the native terminal background");
"that are nearly identical to the native terminal background");
DEFINE_string(space, u8"\u00a0", "The empty character to use when printing. "
"By default this is a utf8 non-breaking space");
DEFINE_bool(spectrum, false, "Show color spectrum graph");
DEFINE_bool(screencast, false, "Screencast desktop. "
"Use arrow keys to pan and +/- to zoom.");
DEFINE_bool(sixel256, false, "Use sixel graphics (256 colors)");
DEFINE_bool(sixel16, false, "Use sixel graphics (16 colors)");
DEFINE_bool(sixel2, false, "Use sixel graphics (2 colors)");
Expand All @@ -70,7 +73,8 @@ void PrintImageSixel256(std::ostream& os, const Graphic& graphic) {
int code = to_index(graphic.Get(x, y).Copy().Opacify(bg));
out.PrintPixel(code);
}
out.LineFeed();
if (y < height - 1)
out.LineFeed();
}
out.End();
}
Expand All @@ -89,7 +93,8 @@ void PrintImageSixel16(std::ostream& os, const Graphic& graphic) {
int code = to_index(graphic.Get(x, y).Copy().Opacify(bg));
out.PrintPixel(code);
}
out.LineFeed();
if (y < height - 1)
out.LineFeed();
}
out.End();
}
Expand All @@ -107,7 +112,8 @@ void PrintImageSixel2(std::ostream& os, const Graphic& graphic) {
int code = to_index(graphic.Get(x, y).Copy().Opacify(bg));
out.PrintPixel(code);
}
out.LineFeed();
if (y < height - 1)
out.LineFeed();
}
out.End();
}
Expand All @@ -127,7 +133,8 @@ void PrintImageXterm256(std::ostream& os, const Graphic& graphic) {
out << FLAGS_space;
}
out.Reset();
out << "\n";
if (y < graphic.height() - 1)
out << "\n";
}
}

Expand All @@ -145,7 +152,8 @@ void PrintImageXterm256Unicode(std::ostream& os, const Graphic& graphic) {
out << kUpperHalfBlock;
}
out.Reset();
out << "\n";
if (y < height - 2)
out << "\n";
}
}

Expand All @@ -162,7 +170,8 @@ void PrintImageMacterm(std::ostream& os, const Graphic& graphic) {
out << color.symbol();
}
out.Reset();
out << "\n";
if (y < height - 2)
out << "\n";
}
}

Expand All @@ -179,7 +188,8 @@ void PrintImageNoColor(std::ostream& os, const Graphic& graphic) {
os << quantizer.Quantize(static_cast<int>(pixel.grey() * 255));
}
}
cout << "\n";
if (y < graphic.height() - 1)
cout << "\n";
}
}

Expand Down Expand Up @@ -241,6 +251,11 @@ int main(int argc, char** argv) {
exit(0);
}

if (FLAGS_screencast) {
artiste.PrintX11(X11());
exit(0);
}

// Otherwise get an arg.
if (argc < 2) {
fprintf(stderr, "Missing file argument.\n"
Expand All @@ -250,12 +265,13 @@ int main(int argc, char** argv) {
}
string path = argv[1];
string extension = GetExtension(path);
string uri_sig = "://"; // Given this string signature, assume that it's a video stream
if (extension == "png") {
artiste.PrintImage(LoadPNG(path));
} else if (extension == "jpg" || extension == "jpeg") {
artiste.PrintImage(LoadJPEG(path));
} else if (extension == "mov" || extension == "mp4" || extension == "flv" ||
extension == "avi" || extension == "mkv") {
extension == "avi" || extension == "mkv" || path.find(uri_sig) != string::npos) {
artiste.PrintMovie(Movie(path));
} else {
fprintf(stderr, "Unknown Filetype: %s\n", extension.data());
Expand Down
3 changes: 3 additions & 0 deletions src/hiptext/artiste.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "hiptext/unicode.h"

class Movie;
class X11;
class Graphic;

using RenderAlgorithm = std::function<void(std::ostream&, const Graphic&)>;
Expand All @@ -24,6 +25,7 @@ class Artiste { // The one who lives in your terminal.

void PrintImage(Graphic graphic);
void PrintMovie(Movie movie);
void PrintX11(X11 x11);

void GenerateSpectrum();

Expand All @@ -33,6 +35,7 @@ class Artiste { // The one who lives in your terminal.
void ShowCursor();
void HideCursor();
void ResetCursor();
void ClearScreen();

private:
void ComputeDimensions(double media_ratio);
Expand Down
24 changes: 24 additions & 0 deletions src/hiptext/input.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef HIPTEXT_INPUT_H_
#define HIPTEXT_INPUT_H_

#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/termios.h>


class Input {
public:
explicit Input();
Input(const Input& input);

void InitializeMain();
int KbHit();
int GetCh();
void Destructor();

private:
struct termios backup;
};

#endif // HIPTEXT_INPUT_H_
72 changes: 72 additions & 0 deletions src/hiptext/x11.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef HIPTEXT_X11_H_
#define HIPTEXT_X11_H_

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "hiptext/graphic.h"
#include "hiptext/input.h"

class X11 {
public:
explicit X11();
X11(X11&& x11);
X11(const X11& x11) = delete;
void operator=(const X11& x11) = delete;

Graphic Next();

inline int width() const { return width_; }
inline int height() const { return height_; }
inline bool done() const { return done_; }

// Make C++11 range-based loops work.
struct iterator {
Graphic operator*() { return x11_->Next(); }
const iterator& operator++() { return *this; }
bool operator!=(const iterator&) const { return !x11_->done(); }
X11* x11_;
};
iterator begin() { return iterator{this}; }
iterator end() { return iterator{this}; }

void InitializeMain();
void TermUpdate(int width, int height);
void CreateImage();
void DestroyImage();
bool HandleInput();
void Contain();
void Zoom(int);
void WaitABit(int);

double zoom_factor = 3.0 / 2.0;

int term_width;
int term_height;
int grab_x = 0;
int grab_y = 0;
int grab_width;
int grab_height;
// The number of X pixels representing a TTY 'pixel'
int tty_pixel_x_size;
int tty_pixel_y_size;

private:
bool IsPointerPixel(int x, int y, int pointer_x, int pointer_y);

bool done_ = false; // True when media is complete.

int width_; // Desired final size. Defaults to natural context.
int height_;

char *dpyname = ":0";
Display *dpy;
Screen *scr;
XImage *ximage;
unsigned depth = 0;

Input input;
GC gc;
};

#endif // HIPTEXT_X11_H_
41 changes: 41 additions & 0 deletions src/input.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

#include "hiptext/input.h"

Input::Input() {}

void Input::InitializeMain() {
struct termios raw;

tcgetattr(0, &backup);
raw = backup;

// Allow individual keys to be read(), rather than waiting for a newline char
raw.c_lflag &= ~ICANON;
// Prevent keypresses being echoed to the current cursor position
raw.c_lflag &= ~ECHO;

tcsetattr(0, TCSANOW, &raw);
}

int Input::KbHit(){
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}

int Input::GetCh(){
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}

void Input::Destructor() {
tcsetattr(0, TCSADRAIN, &backup);
}

Loading