cslarsen / jp2a

Converts jpg images to ASCII
GNU General Public License v2.0
797 stars 71 forks source link

jp2a with half carriage feed? #14

Open gatzke opened 3 years ago

gatzke commented 3 years ago

I had a bit of nostalgia recently and started a quest to find pre-ascii typewriter art using half carriage feeds to partially overlap lines.

I did find some folks do overstrike art, re-running the full line with text overstrikes.

I have not yet dug into your jp2a utility, but I wonder if you think this could be a possible (easy) modification or option? I am not super familiar with the area so this may already exist. Overstrike, half returns, etc.

A half return would complicate things because we can't display easily so you have to have a display app or write the resulting output to PDF maybe?

I am a MATLAB junkie, so I copied in an example of what I am talking about. I tested it in octave online as well and it seems to render for me with a half step. https://octave-online.net/

Thanks for your utility!

Ed Gatzke

BTW, I tried to email csl@csl.name and it bounced. ???

subplot(2,1,1);subplot(1,1,1) f=figure(1) axis off axis([0 1 0 1]) fs=14 % Draw some text: t=text(.1,.7,'This is a test','FontName','Arial','FontSize',fs)

% Draw some two-line text: t=text(.1,.5,sprintf('This is a test \nThis is a test'),'FontName','Arial','FontSize',fs)

% Overlap two lines, need sprintf as it affects text placemnt t=text(.27,.5,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs) dy=.063 % This value depends on figure size, WTF? t=text(.27,.5-dy,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs)

t=text(.1,.2,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs) t=text(.1,.2-dy/2,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs) t=text(.1,.2-dy,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs)

image

Talinx commented 3 years ago

Half carriage has to be supported by the terminal, as far as I can tell most terminal emulators do not support it. Instead one can use HTML. jp2a does support HTML output and with some CSS it can be displayed like half carriage would look. Bash script (3 arguments: first is where the HTML file should be stored, the other two are the input images):

#!/bin/bash
if [ $# -eq 3 ]
then
    if [ -e "$1" ]
    then
        echo "$1 already exists"
    else
        echo "<!DOCTYPE html>
<html>
 <head>
 <meta charset=\"utf-8\">
 <title>jp2a&nbsp;converted&nbsp;image&nbsp;half&nbsp;carriage</title>
  <style>
body {
background-color: black;
}
.ascii {
   font-family: Courier;
   color: white;
   font-size: 8pt;
   line-height: 1.2em;
   font-weight: bold;
}
.first {
  position: fixed;
  top: 0;
  left: 0;
}
.second {
  position: fixed;
  top: 0.6em;
  left: 0;
}
  </style>
 </head>
<body>
<div class='ascii first'><pre>" > "$1"
        jp2a --html --html-raw "$2" >> "$1"
        echo "</pre>
</div>
<div class='ascii second'><pre>" >> "$1"
        jp2a --html --html-raw "$3" >> "$1"
        echo "</pre>
</div>
</body>
</html>" >> "$1"
    fi
else
    echo "Usage: $0 <output> <input A> <input B>"
fi

The second image appears 0.6em below the first, where 0.6em is half the line-height.

gatzke commented 3 years ago

Thanks so much!

It looks like your (genius) script doubles the ASCII image with overlap. I don't think it renders the optimal overlapped image, but I could be wrong.

Rendering two separate ASCII files may be tricky. Normal jp2a can analyze chunks of the image since they are all independent. If characters overlap, other parts of time output are affected. The output optimization becomes trickier.

Put a half horizontal space in one output file and then every output character affects the overall rendering. I think some typewriters had that level of horizontal spacing control back in the day.

Thanks again!

Rabbit demos with your script:

image

image

gatzke commented 3 years ago

Worked some awful Matlab code to run simple random optimization of the ASCII overlap image. It does not shift the odd rows half a column but I may add that too.

image

Warning, this code is turrible. ;-)

close all nx=21 ny=27 C=64+randi(26,6,6)

C=59+randi(31,6,6)

%char(32:1:126) C=31+randi(126-32,ny,nx)

C=zeros(ny,nx)+32 best=99999

h=imread('rabbit.jpg'); hh=h(:,:,1)+h(:,:,2)+h(:,:,3); %whos h hh spy(hh>225) spy(hh(250:350,100:200)>225) spy(hh(150:450,100:400)>225) a=hh(150:450,100:400)>225;

for k=1:3000 % k=1

%close all

subplot(2,1,1);subplot(1,1,1) f=figure(1); pos=get(f,'Position'); %set(f,'Position',[1200 pos(2) pos(3) pos(4)])

axis off axis([0 1 0 1]); fs=18; % Draw some text: % t=text(.1,.7,'This is a test','FontName','Arial','FontSize',fs) % % Draw some two-line text: % t=text(.1,.5,sprintf('This is a test \nThis is a test'),'FontName','Arial','FontSize',fs) % % Overlap two lines, need sprintf as it affects text placemnt % t=text(.27,.5,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs) % dy=.063 % This value depends on figure size, WTF? % t=text(.27,.5-dy,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs)

dy=.063; % This value depends on figure size, WTF? x=-.168; y=1.03; %t=text(x,y,sprintf('This is a test \n This is a test'),'FontName','Courier','FontSize',fs) %t=text(x,y-dy/2,sprintf('This is a test \n '),'FontName','Courier','FontSize',fs) %return

% t=text(x,y,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-dy/2,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-1.5dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-2dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-2.5*dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs)

%char(32:1:126) %char(48:1:58) % 10 digits %char(65:1:90) % 26 caps xs=301; ys=301;

%char(C)

% Replace every \ (92) and _ (95) with space (32) C=C.(C~=92)+(C==92)32; C=C.(C~=95)+(C==95)32; C=C.(C~=91)+(C==91)32; C=C.(C~=123)+(C==123)32;

for i=1:ny str=[ char(C(i,:)) '\n']; %str=['ABCDEF\n']; t=text(x,y-dy*(i-1)/2,sprintf(str),'FontName','Courier','FontSize',fs,'FontWeight','Bold'); end

%pos=get(f,'Position') %set(f,'Position',[pos(1) 150 160 160]); F = getframe(gcf); [g, Map] = frame2im(F);

%print -dbmp fig.bmp %g=imread('fig.bmp'); gg=g(:,:,1)+g(:,:,2)+g(:,:,3);

spy(gg<150)

b=gg(1:xs,1:ys); b=b<150; spy(b)

%whos a b; %return

subplot(2,2,1) spy(a) subplot(2,2,2) spy(b) pos=get(f,'Position'); %set(f,'Position',[1200 pos(2) pos(3) pos(4)])

norm(a-b); val=-sum(sum(a.b))-sum(sum((1-a).(1-b)));

if val<best BESTC=C; best=val; bb=b; disp(['New improved image, value is: ' num2str(val) ' at itaration ' num2str(k)]); else C=OC;

end [row,col]=size(C); %char(32:1:126) %C(randi(row),randi(col))=59+randi(31,1,1) OC=C; C(randi(row),randi(col))=31+randi(125-32,1,1);

end %END BIG LOOP

%disp(char(BESTC)) best subplot(2,2,3) spy(bb) subplot(2,2,4) spy((1-a).*(1-bb)) spy(b-a)

str=' ' for m=1:size(a,1) for n=1:size(a,2) if a(m,n)==1 str(1,n)='1'; else str(1,n)='0'; end end %disp(str); end

save BESTC BESTC

gatzke commented 3 years ago

Assuming you have a half-space along with a half-line feed gives a slightly better rendering IMHO.

image

close all nx=21 ny=27

%nx=3 % For testing %ny=3

C=64+randi(26,6,6)

C=59+randi(31,6,6)

%char(32:1:126) C=31+randi(126-32,ny,nx)

C=zeros(ny,nx)+32 best=99999

h=imread('rabbit.jpg'); hh=h(:,:,1)+h(:,:,2)+h(:,:,3); %whos h hh spy(hh>225) spy(hh(250:350,100:200)>225) spy(hh(150:450,100:400)>225) a=hh(150:450,100:400)>225;

for k=1:4000 %for k=1:30 % k=1

%close all

subplot(2,1,1);subplot(1,1,1) f=figure(1); pos=get(f,'Position'); %set(f,'Position',[1200 pos(2) pos(3) pos(4)])

axis off axis([0 1 0 1]); fs=18; % Draw some text: % t=text(.1,.7,'This is a test','FontName','Arial','FontSize',fs) % % Draw some two-line text: % t=text(.1,.5,sprintf('This is a test \nThis is a test'),'FontName','Arial','FontSize',fs) % % Overlap two lines, need sprintf as it affects text placemnt % t=text(.27,.5,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs) % dy=.063 % This value depends on figure size, WTF? % t=text(.27,.5-dy,sprintf('This is a test \n '),'FontName','Arial','FontSize',fs)

dy=.063; % This value depends on figure size, WTF? dx=0.0145; x=-.168; y=1.03; %t=text(x,y,sprintf('This is a test \n This is a test'),'FontName','Courier','FontSize',fs) %t=text(x,y-dy/2,sprintf('This is a test \n '),'FontName','Courier','FontSize',fs) %return

% t=text(x,y,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-dy/2,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-1.5dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-2dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs) % t=text(x,y-2.5*dy,sprintf('ABCDE\n'),'FontName','Arial','FontSize',fs)

%char(32:1:126) %char(48:1:58) % 10 digits %char(65:1:90) % 26 caps xs=301; ys=301;

%char(C)

% Replace every \ (92) and _ (95) with space (32) C=C.(C~=92)+(C==92)32; C=C.(C~=95)+(C==95)32; C=C.(C~=91)+(C==91)32; C=C.(C~=123)+(C==123)32;

for i=1:ny str=[ char(C(i,:)) '\n']; %str=['ABCDEF\n']; %str=['XXXXXX\n']; if mod(i,2)==1 % Odd case t=text(x,y-dy(i-1)/2,sprintf(str),'FontName','Courier','FontSize',fs,'FontWeight','Bold'); else t=text(x+dx,y-dy(i-1)/2,sprintf(str),'FontName','Courier','FontSize',fs,'FontWeight','Bold'); end

end

%pos=get(f,'Position') %set(f,'Position',[pos(1) 150 160 160]); F = getframe(gcf); [g, Map] = frame2im(F);

%print -dbmp fig.bmp %g=imread('fig.bmp'); gg=g(:,:,1)+g(:,:,2)+g(:,:,3);

spy(gg<150)

b=gg(1:xs,1:ys); b=b<150; spy(b)

%whos a b; %return

subplot(2,2,1) spy(a) subplot(2,2,2) spy(b) pos=get(f,'Position'); %set(f,'Position',[1200 pos(2) pos(3) pos(4)])

norm(a-b); val=-sum(sum(a.b))-sum(sum((1-a).(1-b)));

if val<best BESTC=C; best=val; bb=b; disp(['New improved image, value is: ' num2str(val) ' at iteration ' num2str(k)]); else C=OC;

end [row,col]=size(C); %char(32:1:126) %C(randi(row),randi(col))=59+randi(31,1,1) OC=C; C(randi(row),randi(col))=31+randi(125-32,1,1);

end %END BIG LOOP

%disp(char(BESTC)) best subplot(2,2,3) spy(bb) subplot(2,2,4) spy((1-a).*(1-bb)) spy(b-a)

str=' ' for m=1:size(a,1) for n=1:size(a,2) if a(m,n)==1 str(1,n)='1'; else str(1,n)='0'; end end %disp(str); end

save BESTC BESTC