├── obs ├── debian │ ├── compat │ ├── ipe.install │ ├── ipe.menu │ ├── ipe.lintian-overrides │ ├── ipe.desktop │ ├── rules │ ├── copyright │ ├── control │ └── changelog ├── make-specs.sh └── ipe.spec ├── matplotlib ├── .gitignore ├── past │ ├── tests │ │ ├── line_demo_dash_control.py │ │ ├── image_demo.py │ │ ├── watermark_image.py │ │ ├── watermark_image2.py │ │ ├── fill_demo.py │ │ ├── image_demo_clip_path.py │ │ ├── two_scales.py │ │ ├── barh_demo.py │ │ ├── legend_demo.py │ │ ├── clip_test.py │ │ ├── joinstyle.py │ │ ├── power_norm_demo.py │ │ ├── histogram_path_demo.py │ │ ├── color_cycle_demo.py │ │ ├── barchart_demo.py │ │ ├── date_demo.py │ │ ├── donut_demo.py │ │ ├── colormaps_reference.py │ │ ├── line_styles_reference.py │ │ └── collections_demo.py │ └── run_test.py ├── tests │ ├── line_demo_dash_control.py │ ├── fill_demo.py │ ├── image_demo_clip_path.py │ ├── two_scales.py │ ├── barh_demo.py │ ├── legend_demo.py │ ├── watermark_image.py │ ├── joinstyle.py │ ├── power_norm_demo.py │ ├── histogram_path_demo.py │ ├── barchart_demo.py │ ├── clip_test.py │ ├── color_cycle_demo.py │ ├── donut_demo.py │ ├── line_styles_reference.py │ ├── colormaps_reference.py │ └── collections_demo.py ├── run_test.py ├── README.md └── backend_ipe.py ├── appimage ├── ipe.png ├── appimage.lua ├── startipe.sh ├── Ipe.desktop ├── Ipe.appdata.xml ├── README.md ├── setup.sh ├── appimage.yml └── recipe.sh ├── snap ├── setup │ └── gui │ │ ├── ipe.desktop │ │ └── icon.png ├── opencage │ └── opencage.sh ├── wrapper │ ├── wrapper.sh │ └── tlmgr.sh ├── snap │ └── plugins │ │ └── x-texlive.py ├── README.md └── snapcraft.yaml ├── pdftoipe ├── compile_on_windows.pdf ├── Makefile ├── parseargs.h ├── pdftoipe.1 ├── xmloutputdev.h ├── parseargs.cc ├── readme.txt ├── pdftoipe.cpp └── xmloutputdev.cpp ├── .gitignore ├── ipe5toxml ├── Makefile └── ipe5toxml.1 ├── figtoipe ├── Makefile ├── readme.txt └── figtoipe.1 ├── ipepython ├── setup.py ├── test.py └── readme.md ├── annotate ├── README.md └── annotate.py ├── svgtoipe ├── test_svg.py ├── svgtoipe.1 └── readme.txt ├── poweripe ├── readme.md ├── poweripe.py └── demo-presentation.ipe └── README.md /obs/debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /matplotlib/.gitignore: -------------------------------------------------------------------------------- 1 | __pycahce__/ 2 | out/ 3 | tmp.py 4 | *.pyc 5 | 6 | -------------------------------------------------------------------------------- /appimage/ipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otfried/ipe-tools/HEAD/appimage/ipe.png -------------------------------------------------------------------------------- /snap/setup/gui/ipe.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Ipe 3 | Exec=ipe 4 | Type=Application 5 | -------------------------------------------------------------------------------- /snap/setup/gui/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otfried/ipe-tools/HEAD/snap/setup/gui/icon.png -------------------------------------------------------------------------------- /obs/debian/ipe.install: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/lib/lib*.so 3 | usr/share/ipe 4 | usr/share/man 5 | usr/lib/ipe/*/ipelets 6 | -------------------------------------------------------------------------------- /pdftoipe/compile_on_windows.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otfried/ipe-tools/HEAD/pdftoipe/compile_on_windows.pdf -------------------------------------------------------------------------------- /obs/debian/ipe.menu: -------------------------------------------------------------------------------- 1 | ?package(ipe):needs="X11" section="Applications/Graphics"\ 2 | title="Ipe" command="/usr/bin/ipe" 3 | -------------------------------------------------------------------------------- /appimage/appimage.lua: -------------------------------------------------------------------------------- 1 | -- Special settings for the Ipe appimage 2 | prefs.browser = "unset XDG_DATA_DIRS && unset LD_LIBRARY_PATH && xdg-open %s" 3 | -------------------------------------------------------------------------------- /obs/debian/ipe.lintian-overrides: -------------------------------------------------------------------------------- 1 | # Several scripts use the non-standard interpreter ipescript, shipped in package ipe. 2 | # 3 | ipe: unusual-interpreter 4 | -------------------------------------------------------------------------------- /appimage/startipe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CMD=$1 3 | if [ "x${CMD}x" == "xx" ]; then 4 | ipe -style fusion "$@" 5 | else 6 | shift 7 | $CMD "$@" 8 | fi 9 | -------------------------------------------------------------------------------- /appimage/Ipe.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Ipe 4 | GenericName=drawing program 5 | Icon=ipe 6 | Exec=startipe.sh 7 | Terminal=false 8 | Categories=Graphics; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | pdftoipe/pdftoipe 3 | figtoipe/figtoipe 4 | ipe5toxml/ipe5toxml 5 | build 6 | *.AppImage 7 | AppImageKit 8 | Ipe.AppDir 9 | *.pyc 10 | *.snap 11 | test 12 | tmpipe* 13 | *.pptx 14 | *.exe 15 | *.pdf 16 | *.svg 17 | -------------------------------------------------------------------------------- /snap/opencage/opencage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SNAP="/snap/ipe/current" 3 | COMMAND=$1 4 | shift 5 | export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu" 6 | exec $SNAP/bin/$COMMAND $@ 7 | -------------------------------------------------------------------------------- /snap/wrapper/wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH="$SNAP/texlive/bin/x86_64-linux:$PATH" 3 | export TEXMFHOME="$SNAP_USER_COMMON/texmf" 4 | export IPELATEXDIR="$SNAP_USER_DATA/latexrun" 5 | export IPELETPATH="$SNAP_USER_COMMON/ipelets:_" 6 | export IPESTYLES="$SNAP_USER_COMMON/styles:_" 7 | exec "$@" 8 | -------------------------------------------------------------------------------- /obs/debian/ipe.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Name=Ipe drawing editor 5 | GenericName=PDF Figure Editor 6 | Comment=Create your drawings in PDF format 7 | Exec=ipe 8 | Icon=ipe 9 | Terminal=false 10 | Categories=Graphics;2DGraphics;RasterGraphics; 11 | StartupNotify=true 12 | -------------------------------------------------------------------------------- /matplotlib/past/tests/line_demo_dash_control.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | x = np.linspace(0, 10) 7 | line, = plt.plot(x, np.sin(x), '--', linewidth=2) 8 | 9 | dashes = [10, 5, 100, 5] # 10 points on, 5 off, 100 on, 5 off 10 | line.set_dashes(dashes) 11 | 12 | 13 | -------------------------------------------------------------------------------- /matplotlib/past/tests/image_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple demo of the imshow function. 3 | """ 4 | import matplotlib.pyplot as plt 5 | import matplotlib.cbook as cbook 6 | 7 | datafile = cbook.get_sample_data('ada.png', asfileobj=False) 8 | image = plt.imread(datafile) 9 | 10 | plt.imshow(image) 11 | plt.axis('off') # clear x- and y-axes 12 | -------------------------------------------------------------------------------- /matplotlib/tests/line_demo_dash_control.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from matplotlib import use 4 | use('module://backend_ipe') 5 | 6 | 7 | x = np.linspace(0, 10) 8 | line, = plt.plot(x, np.sin(x), '--', linewidth=2) 9 | 10 | dashes = [10, 5, 100, 5] # 10 points on, 5 off, 100 on, 5 off 11 | line.set_dashes(dashes) 12 | 13 | 14 | # plt.show() 15 | plt.savefig('line_demo_dash_control.ipe') 16 | -------------------------------------------------------------------------------- /ipe5toxml/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for ipe5toxml 3 | # 4 | 5 | ifdef COMSPEC 6 | TARGET = ipe5toxml.exe 7 | LDFLAGS = -mconsole 8 | else 9 | TARGET = ipe5toxml 10 | endif 11 | 12 | LIBS = -lm 13 | 14 | all: $(TARGET) 15 | 16 | sources = ipe5toxml.c 17 | 18 | objects = ipe5toxml.o 19 | 20 | $(TARGET): $(objects) 21 | $(CC) $(LDFLAGS) -o $(TARGET) $(objects) $(LIBS) 22 | 23 | .PHONY: clean 24 | clean: 25 | @-rm -f $(objects) $(TARGET) 26 | 27 | -------------------------------------------------------------------------------- /matplotlib/run_test.py: -------------------------------------------------------------------------------- 1 | from glob import glob 2 | from os.path import exists 3 | from subprocess import run 4 | 5 | 6 | if not exists(outdir := "test_outputs"): 7 | run(f"mkdir {outdir}", shell=True) 8 | 9 | if exists(f"tests/{outdir}"): 10 | run(f"rm -rf tests/{outdir}", shell=True) 11 | 12 | for f in (files := glob('tests/*.py')): 13 | print(f"python {f}") 14 | run(["python", f"{f}"]) 15 | run(f"mv *.ipe {outdir}", shell=True) 16 | run(f"mv {outdir} tests", shell=True) 17 | -------------------------------------------------------------------------------- /ipe5toxml/ipe5toxml.1: -------------------------------------------------------------------------------- 1 | .TH IPE5TOXML "1" "December 2011" "Ipe" "User Commands" 2 | 3 | .SH NAME 4 | ipe5toxml \- Convert Ipe 5 file to Ipe 6 format 5 | 6 | .SH SYNOPSIS 7 | .B ipe5toxml 8 | \fIfile.ipe file.xml\fR 9 | 10 | .SH DESCRIPTION 11 | \fBipe5toxml\fR converts an Ipe version 5 format file to one understood by Ipe version 6. 12 | Use \fBipe6upgrade\fR to convert the output XML file to one understood by Ipe version 7. 13 | 14 | .SH AUTHOR 15 | Otfried Cheong 16 | 17 | .SH "SEE ALSO" 18 | \fBipe6upgrade\fR(1) 19 | -------------------------------------------------------------------------------- /matplotlib/past/tests/watermark_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use a Text as a watermark 3 | """ 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | mpl.rcParams['ipe.preamble'] = r"\usepackage{times}" 9 | 10 | fig, ax = plt.subplots() 11 | ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') 12 | ax.grid() 13 | 14 | # position bottom right 15 | fig.text(0.95, 0.05, 'Property of MPL', 16 | fontsize=50, color='gray', 17 | ha='right', va='bottom', alpha=0.5) 18 | 19 | -------------------------------------------------------------------------------- /matplotlib/past/tests/watermark_image2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Use a PNG file as a watermark 4 | """ 5 | import numpy as np 6 | import matplotlib.cbook as cbook 7 | import matplotlib.image as image 8 | import matplotlib.pyplot as plt 9 | 10 | datafile = cbook.get_sample_data('logo2.png', asfileobj=False) 11 | im = image.imread(datafile) 12 | im[:,:,-1] = 0.5 # set the alpha channel 13 | 14 | fig, ax = plt.subplots() 15 | 16 | ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') 17 | ax.grid() 18 | fig.figimage(im, 10, 10) 19 | -------------------------------------------------------------------------------- /matplotlib/past/tests/fill_demo.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Demo of the fill function with a few features. 4 | 5 | In addition to the basic fill plot, this demo shows a few optional features: 6 | 7 | * Multiple curves with a single command. 8 | * Setting the fill color. 9 | * Setting the opacity (alpha value). 10 | """ 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | x = np.linspace(0, 2 * np.pi, 100) 15 | y1 = np.sin(x) 16 | y2 = np.sin(3 * x) 17 | plt.fill(x, y1, 'b', x, y2, 'r', alpha=0.3) 18 | 19 | -------------------------------------------------------------------------------- /matplotlib/past/tests/image_demo_clip_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demo of image that's been clipped by a circular patch. 3 | """ 4 | import matplotlib.pyplot as plt 5 | import matplotlib.patches as patches 6 | import matplotlib.cbook as cbook 7 | 8 | datafile = cbook.get_sample_data('grace_hopper.jpg', asfileobj=False) 9 | image = plt.imread(datafile) 10 | fig, ax = plt.subplots() 11 | im = ax.imshow(image) 12 | patch = patches.Circle((260, 200), radius=200, transform=ax.transData) 13 | im.set_clip_path(patch) 14 | 15 | plt.axis('off') 16 | -------------------------------------------------------------------------------- /matplotlib/past/tests/two_scales.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | fig, ax1 = plt.subplots() 7 | t = np.arange(0.01, 10.0, 0.01) 8 | s1 = np.exp(t) 9 | ax1.plot(t, s1, 'b-') 10 | ax1.set_xlabel('time (s)') 11 | # Make the y-axis label and tick labels match the line color. 12 | ax1.set_ylabel('exp', color='b') 13 | for tl in ax1.get_yticklabels(): 14 | tl.set_color('b') 15 | 16 | 17 | ax2 = ax1.twinx() 18 | s2 = np.sin(2*np.pi*t) 19 | ax2.plot(t, s2, 'r.') 20 | ax2.set_ylabel('sin', color='r') 21 | for tl in ax2.get_yticklabels(): 22 | tl.set_color('r') 23 | 24 | 25 | -------------------------------------------------------------------------------- /matplotlib/past/tests/barh_demo.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Simple demo of a horizontal bar chart. 4 | """ 5 | import matplotlib.pyplot as plt; plt.rcdefaults() 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | 9 | 10 | # Example data 11 | people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim') 12 | y_pos = np.arange(len(people)) 13 | performance = 3 + 10 * np.random.rand(len(people)) 14 | error = np.random.rand(len(people)) 15 | 16 | plt.barh(y_pos, performance, xerr=error, align='center', alpha=0.4) 17 | plt.yticks(y_pos, people) 18 | plt.xlabel('Performance') 19 | plt.title('How fast do you want to go today?') 20 | 21 | 22 | -------------------------------------------------------------------------------- /matplotlib/past/tests/legend_demo.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | mpl.rcParams['ipe.textsize'] = True 5 | 6 | # Make some fake data. 7 | a = b = np.arange(0,3, .02) 8 | c = np.exp(a) 9 | d = c[::-1] 10 | 11 | # Create plots with pre-defined labels. 12 | plt.plot(a, c, 'k--', label='Model length') 13 | plt.plot(a, d, 'k:', label='Data length') 14 | plt.plot(a, c+d, 'k', label='Total message length') 15 | 16 | legend = plt.legend(loc='upper center', shadow=True, fontsize='x-large') 17 | 18 | # Put a nicer background color on the legend. 19 | legend.get_frame().set_facecolor('#00FFCC') 20 | 21 | -------------------------------------------------------------------------------- /matplotlib/tests/fill_demo.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Demo of the fill function with a few features. 4 | 5 | In addition to the basic fill plot, this demo shows a few optional features: 6 | 7 | * Multiple curves with a single command. 8 | * Setting the fill color. 9 | * Setting the opacity (alpha value). 10 | """ 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | from matplotlib import use 14 | use('module://backend_ipe') 15 | 16 | x = np.linspace(0, 2 * np.pi, 100) 17 | y1 = np.sin(x) 18 | y2 = np.sin(3 * x) 19 | plt.fill(x, y1, 'b', x, y2, 'r', alpha=0.3) 20 | 21 | # plt.show() 22 | plt.savefig('fill_demo.ipe') 23 | -------------------------------------------------------------------------------- /matplotlib/tests/image_demo_clip_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demo of image that's been clipped by a circular patch. 3 | """ 4 | import matplotlib.pyplot as plt 5 | import matplotlib.patches as patches 6 | import matplotlib.cbook as cbook 7 | from matplotlib import use 8 | use('module://backend_ipe') 9 | 10 | datafile = cbook.get_sample_data('grace_hopper.jpg', asfileobj=False) 11 | image = plt.imread(datafile) 12 | fig, ax = plt.subplots() 13 | im = ax.imshow(image) 14 | patch = patches.Circle((260, 200), radius=200, transform=ax.transData) 15 | im.set_clip_path(patch) 16 | 17 | plt.axis('off') 18 | # plt.show() 19 | plt.savefig('image_demo_clip_path.ipe') 20 | -------------------------------------------------------------------------------- /matplotlib/tests/two_scales.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from matplotlib import use 4 | use('module://backend_ipe') 5 | 6 | 7 | fig, ax1 = plt.subplots() 8 | t = np.arange(0.01, 10.0, 0.01) 9 | s1 = np.exp(t) 10 | ax1.plot(t, s1, 'b-') 11 | ax1.set_xlabel('time (s)') 12 | # Make the y-axis label and tick labels match the line color. 13 | ax1.set_ylabel('exp', color='b') 14 | for tl in ax1.get_yticklabels(): 15 | tl.set_color('b') 16 | 17 | 18 | ax2 = ax1.twinx() 19 | s2 = np.sin(2*np.pi*t) 20 | ax2.plot(t, s2, 'r.') 21 | ax2.set_ylabel('sin', color='r') 22 | for tl in ax2.get_yticklabels(): 23 | tl.set_color('r') 24 | 25 | # plt.show() 26 | plt.savefig('two_scales.ipe') 27 | -------------------------------------------------------------------------------- /matplotlib/tests/barh_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple demo of a horizontal bar chart. 3 | """ 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from matplotlib import use 8 | 9 | 10 | plt.rcdefaults() 11 | use('module://backend_ipe') 12 | 13 | # Example data 14 | people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim') 15 | y_pos = np.arange(len(people)) 16 | performance = 3 + 10 * np.random.rand(len(people)) 17 | error = np.random.rand(len(people)) 18 | 19 | plt.barh(y_pos, performance, xerr=error, align='center', alpha=0.4) 20 | plt.yticks(y_pos, people) 21 | plt.xlabel('Performance') 22 | plt.title('How fast do you want to go today?') 23 | 24 | plt.savefig('barh_demo.ipe', format='ipe') 25 | -------------------------------------------------------------------------------- /matplotlib/tests/legend_demo.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib as mpl 4 | mpl.use('module://backend_ipe') 5 | 6 | 7 | mpl.rcParams['ipe.textsize'] = True 8 | 9 | # Make some fake data. 10 | a = b = np.arange(0, 3, .02) 11 | c = np.exp(a) 12 | d = c[::-1] 13 | 14 | # Create plots with pre-defined labels. 15 | plt.plot(a, c, 'k--', label='Model length') 16 | plt.plot(a, d, 'k:', label='Data length') 17 | plt.plot(a, c+d, 'k', label='Total message length') 18 | 19 | legend = plt.legend(loc='upper center', shadow=True, fontsize='x-large') 20 | 21 | # Put a nicer background color on the legend. 22 | legend.get_frame().set_facecolor('#00FFCC') 23 | 24 | plt.savefig('legend_demo.ipe') 25 | -------------------------------------------------------------------------------- /matplotlib/tests/watermark_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use a Text as a watermark 3 | """ 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from matplotlib import use, rcParams 8 | use('module://backend_ipe') 9 | 10 | rcParams['ipe.preamble'] = r"\usepackage{times}" 11 | # _isy = "/Applications/Ipe.app/Contents/Resources/styles/basic.isy" 12 | # rcParams['ipe.stylesheet'] = _isy 13 | 14 | fig, ax = plt.subplots() 15 | ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') 16 | ax.grid() 17 | 18 | # position bottom right 19 | fig.text(0.95, 0.05, 'Property of MPL', 20 | fontsize=50, color='gray', 21 | ha='right', va='bottom', alpha=0.5) 22 | 23 | # plt.show() 24 | plt.savefig('watermark_image.ipe') 25 | -------------------------------------------------------------------------------- /figtoipe/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # Makefile for building figtoipe 3 | ############################################################################# 4 | 5 | CXX = g++ 6 | CXXFLAGS += -O2 -Wall -W 7 | RM = rm -f 8 | LIBS = -lz 9 | 10 | TARGET = figtoipe 11 | SOURCES = $(TARGET).cpp 12 | SRCDISTFILES = $(TARGET).1 $(SOURCES) README Makefile GPL-2 13 | 14 | all: $(TARGET) 15 | 16 | clean: 17 | -$(RM) $(TARGET) 18 | 19 | $(TARGET): $(SOURCES) 20 | $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) 21 | 22 | dist: 23 | DATE=`date +"%Y%m%d"`; D=/tmp/$(TARGET)-$$DATE; \ 24 | rm -rf $$D; mkdir $$D; \ 25 | cp $(SRCDISTFILES) $$D; \ 26 | tar czvf $$D.tar.gz -C /tmp $(TARGET)-$$DATE 27 | 28 | .PHONY: all 29 | -------------------------------------------------------------------------------- /matplotlib/past/tests/clip_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.cm as cm 3 | import matplotlib.mlab as mlab 4 | import matplotlib.pyplot as plt 5 | from matplotlib.path import Path 6 | from matplotlib.patches import PathPatch 7 | 8 | delta = 0.025 9 | x = y = np.arange(-3.0, 3.0, delta) 10 | X, Y = np.meshgrid(x, y) 11 | Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 12 | Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 13 | Z = Z2-Z1 # difference of Gaussians 14 | 15 | path = Path([[0, 1], [1, 0], [0, -1], [-1, 0], [0, 1]]) 16 | patch = PathPatch(path, facecolor='none') 17 | plt.gca().add_patch(patch) 18 | 19 | im = plt.imshow(Z, interpolation='bilinear', cmap=cm.gray, 20 | origin='lower', extent=[-3,3,-3,3], 21 | clip_path=patch, clip_on=True) 22 | im.set_clip_path(patch) 23 | 24 | -------------------------------------------------------------------------------- /obs/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export IPEPREFIX=/usr 4 | export INSTALL_ROOT=$(shell pwd)/debian/tmp 5 | 6 | #export DH_VERBOSE=1 7 | export DEB_BUILD_MAINT_OPTIONS=hardening=+all 8 | 9 | # libspiro before 201907 apparently had no pkg-config 10 | export SPIRO_LIBS=-lspiro 11 | export SPIRO_CFLAGS= 12 | 13 | # Qt6 hat no pkg-config before 6.3.1 14 | export QT_CFLAGS=-DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB \ 15 | -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets \ 16 | -I/usr/include/x86_64-linux-gnu/qt6/QtGui \ 17 | -I/usr/include/x86_64-linux-gnu/qt6/QtCore \ 18 | -I/usr/include/x86_64-linux-gnu/qt6 19 | export QT_LIBS=-lQt6Widgets -lQt6Gui -lQt6Core 20 | 21 | %: 22 | dh $@ --sourcedirectory=src 23 | 24 | override_dh_auto_build: 25 | dh_auto_build -- all 26 | 27 | override_dh_install: 28 | dh_install 29 | dh_install debian/tmp/usr/lib/lib*.so.* usr/lib 30 | -------------------------------------------------------------------------------- /snap/wrapper/tlmgr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash --posix 2 | # This should be run outside the snap, 3 | # as the Perl in the snap is incomplete and cannot execute tlmgr.pl 4 | 5 | findSnap() { 6 | local source="${BASH_SOURCE[0]}" 7 | while [ -h "$source" ] ; do 8 | local linked="$(readlink "$source")" 9 | local dir="$(cd -P $(dirname "$source") && cd -P $(dirname "$linked") && pwd)" 10 | source="$dir/$(basename "$linked")" 11 | done 12 | (cd -P "$(dirname "$source")/.." && pwd) 13 | } 14 | 15 | export SNAP="$(findSnap)" 16 | 17 | export TEXMFHOME=$HOME/snap/ipe/common/texmf 18 | 19 | TLMGR="$SNAP/texlive/bin/x86_64-linux/tlmgr" 20 | 21 | #echo "SNAP is $SNAP" 22 | #echo "TEXMFHOME is $TEXMFHOME" 23 | 24 | if [ ! -d "$TEXMFHOME" ]; then 25 | echo "Creating personal texlive tree..." 26 | mkdir -p "$TEXMFHOME" 27 | perl $TLMGR init-usertree --usermode 28 | fi 29 | 30 | perl $TLMGR $@ --usermode 31 | -------------------------------------------------------------------------------- /matplotlib/past/tests/joinstyle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Illustrate the three different join styles 3 | """ 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | def plot_angle(ax, x, y, angle, style): 9 | phi = angle/180*np.pi 10 | xx = [x+.5,x,x+.5*np.cos(phi)] 11 | yy = [y,y,y+.5*np.sin(phi)] 12 | ax.plot(xx, yy, lw=8, color='blue', solid_joinstyle=style) 13 | ax.plot(xx[1:], yy[1:], lw=1, color='black') 14 | ax.plot(xx[1::-1], yy[1::-1], lw=1, color='black') 15 | ax.plot(xx[1:2], yy[1:2], 'o', color='red', markersize=3) 16 | ax.text(x,y+.2,'%.0f degrees' % angle) 17 | 18 | fig, ax = plt.subplots() 19 | ax.set_title('Join style') 20 | 21 | for x,style in enumerate((('miter', 'round', 'bevel'))): 22 | ax.text(x, 5, style) 23 | for i in range(5): 24 | plot_angle(ax, x, i, pow(2.0,3+i), style) 25 | 26 | ax.set_xlim(-0.5,2.75) 27 | ax.set_ylim(-0.5,5.5) 28 | 29 | -------------------------------------------------------------------------------- /matplotlib/past/tests/power_norm_demo.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot as plt 2 | import matplotlib.colors as mcolors 3 | import numpy as np 4 | from numpy.random import multivariate_normal 5 | 6 | data = np.vstack([multivariate_normal([10, 10], [[3, 5],[4, 2]], size=100000), 7 | multivariate_normal([30, 20], [[2, 3],[1, 3]], size=1000) 8 | ]) 9 | 10 | gammas = [0.8, 0.5, 0.3] 11 | xgrid = np.floor((len(gammas) + 1.) / 2) 12 | ygrid = np.ceil((len(gammas) + 1.) / 2) 13 | 14 | plt.subplot(xgrid, ygrid, 1) 15 | plt.title('Linear normalization') 16 | plt.hist2d(data[:,0], data[:,1], bins=100) 17 | 18 | for i, gamma in enumerate(gammas): 19 | plt.subplot(xgrid, ygrid, i + 2) 20 | plt.title('Power law normalization\n$(\gamma=%1.1f)$' % gamma) 21 | plt.hist2d(data[:, 0], data[:, 1], 22 | bins=100, norm=mcolors.PowerNorm(gamma)) 23 | 24 | plt.subplots_adjust(hspace=0.39) 25 | 26 | -------------------------------------------------------------------------------- /ipepython/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | # compile options to find Lua and Ipe headers and libraries 4 | lua_includes = [ '-I/usr/include/lua5.3' ] 5 | lua_libs = [ '-llua5.3' ] 6 | 7 | ipe_srcdir = '../../ipe/src' 8 | ipe_libdir = '../../ipe/build/lib' 9 | 10 | ipe_includes = [ '-I%s/include' % ipe_srcdir ] 11 | ipe_libs = [ '-L%s' % ipe_libdir, '-lipelua', '-lipe' ] 12 | 13 | ipemodule = Extension('ipe', 14 | sources = ['ipepython.cpp'], 15 | extra_compile_args = lua_includes + ipe_includes, 16 | extra_link_args = lua_libs + ipe_libs, 17 | ) 18 | 19 | setup(name = 'ipe', 20 | version = '2019.09.10', 21 | description = 'Use Ipelib from Python', 22 | url = 'https://github.com/otfried/ipe-tools/tree/python3/ipepython', 23 | author = 'Otfried Cheong', 24 | author_email = 'ipe@otfried.org', 25 | license = 'GPL3', 26 | ext_modules = [ipemodule], 27 | ) 28 | -------------------------------------------------------------------------------- /annotate/README.md: -------------------------------------------------------------------------------- 1 | annotate.py 2 | ========== 3 | 4 | This Python script takes a PDF file and creates an Ipe document that 5 | shows the pages of the PDF page by page, allowing you to annotate the 6 | PDF document, for instance using ink mode on a tablet or by simply 7 | creating new text objects. 8 | 9 | To run it, you will need the *PyPDF2* library from 10 | https://github.com/mstamy2/PyPDF2. The easiest way to install 11 | *PyPDF2* is using PIP - on Linux it will suffice to say 12 | 13 | ``` 14 | apt-get install python3-pip 15 | pip3 install PyPDF2 16 | ``` 17 | 18 | (Or, if using Python~2, install `python-pip` and call `pip`.) 19 | 20 | Run it with a PDF file as an argument: 21 | 22 | ``` 23 | python3 annotate.py doc.pdf 24 | ``` 25 | 26 | It will create the new file `annotate-doc.ipe`. 27 | 28 | When opening `annotate-doc.ipe` using Ipe, you will need to have the 29 | original PDF file `doc.pdf` available for Ipe. You either have to 30 | copy it into Ipe's Latex directory (e.g. `~/.ipe/latexrun`), or you 31 | have to set the `TEXINPUTS` environment variable. 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /matplotlib/tests/joinstyle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Illustrate the three different join styles 3 | """ 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from matplotlib import use 8 | use('module://backend_ipe') 9 | 10 | 11 | def plot_angle(ax, x, y, angle, style): 12 | phi = angle / 180 * np.pi 13 | xx = [x+.5, x, x + .5 * np.cos(phi)] 14 | yy = [y, y, y + .5 * np.sin(phi)] 15 | ax.plot(xx, yy, lw=8, color='blue', solid_joinstyle=style) 16 | ax.plot(xx[1:], yy[1:], lw=1, color='black') 17 | ax.plot(xx[1::-1], yy[1::-1], lw=1, color='black') 18 | ax.plot(xx[1:2], yy[1:2], 'o', color='red', markersize=3) 19 | ax.text(x, y+.2, '%.0f degrees' % angle) 20 | 21 | 22 | fig, ax = plt.subplots() 23 | ax.set_title('Join style') 24 | 25 | for x, style in enumerate((('miter', 'round', 'bevel'))): 26 | ax.text(x, 5, style) 27 | for i in range(5): 28 | plot_angle(ax, x, i, pow(2.0, 3+i), style) 29 | 30 | ax.set_xlim(-0.5, 2.75) 31 | ax.set_ylim(-0.5, 5.5) 32 | 33 | # plt.show() 34 | plt.savefig('joinstyle.ipe') 35 | -------------------------------------------------------------------------------- /matplotlib/past/tests/histogram_path_demo.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import matplotlib.patches as patches 5 | import matplotlib.path as path 6 | 7 | fig, ax = plt.subplots() 8 | 9 | # histogram our data with numpy 10 | data = np.random.randn(1000) 11 | n, bins = np.histogram(data, 50) 12 | 13 | # get the corners of the rectangles for the histogram 14 | left = np.array(bins[:-1]) 15 | right = np.array(bins[1:]) 16 | bottom = np.zeros(len(left)) 17 | top = bottom + n 18 | 19 | 20 | # we need a (numrects x numsides x 2) numpy array for the path helper 21 | # function to build a compound path 22 | XY = np.array([[left,left,right,right], [bottom,top,top,bottom]]).T 23 | 24 | # get the Path object 25 | barpath = path.Path.make_compound_path_from_polys(XY) 26 | 27 | # make a patch out of it 28 | patch = patches.PathPatch(barpath, facecolor='blue', edgecolor='gray', alpha=0.8) 29 | ax.add_patch(patch) 30 | 31 | # update the view limits 32 | ax.set_xlim(left[0], right[-1]) 33 | ax.set_ylim(bottom.min(), top.max()) 34 | 35 | 36 | -------------------------------------------------------------------------------- /matplotlib/tests/power_norm_demo.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | ======================== 4 | Exploring normalizations 5 | ======================== 6 | 7 | Let's explore various normalization on a multivariate normal distribution. 8 | 9 | """ 10 | 11 | from matplotlib import pyplot as plt, use 12 | import matplotlib.colors as mcolors 13 | import numpy as np 14 | from numpy.random import multivariate_normal 15 | 16 | 17 | use('module://backend_ipe') 18 | 19 | data = np.vstack([ 20 | multivariate_normal([10, 10], [[3, 2], [2, 3]], size=100000), 21 | multivariate_normal([30, 20], [[3, 1], [1, 3]], size=1000) 22 | ]) 23 | 24 | gammas = [0.8, 0.5, 0.3] 25 | 26 | fig, axes = plt.subplots(nrows=2, ncols=2) 27 | 28 | axes[0, 0].set_title('Linear normalization') 29 | axes[0, 0].hist2d(data[:, 0], data[:, 1], bins=100) 30 | 31 | for ax, gamma in zip(axes.flat[1:], gammas): 32 | ax.set_title(r'Power law $(\gamma=%1.1f)$' % gamma) 33 | ax.hist2d(data[:, 0], data[:, 1], 34 | bins=100, norm=mcolors.PowerNorm(gamma)) 35 | 36 | fig.tight_layout() 37 | 38 | plt.savefig('power_norm_demo.ipe') 39 | -------------------------------------------------------------------------------- /obs/debian/copyright: -------------------------------------------------------------------------------- 1 | Ipe 7 extensible graphics editor 2 | 3 | Copyright (c) 1993-2023 Otfried Cheong 4 | 5 | Ipe is free software; you can redistribute it and/or modify it 6 | under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | As a special exception, you have permission to link Ipe with the 11 | CGAL library and distribute executables, as long as you follow the 12 | requirements of the Gnu General Public License in regard to all of 13 | the software in the executable aside from CGAL. 14 | 15 | Ipe is distributed in the hope that it will be useful, but WITHOUT 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 18 | License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Ipe; if not, you can find it at 22 | "http://www.gnu.org/copyleft/gpl.html", or write to the Free 23 | Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 | -------------------------------------------------------------------------------- /snap/snap/plugins/x-texlive.py: -------------------------------------------------------------------------------- 1 | # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- 2 | import os 3 | from subprocess import Popen, PIPE 4 | 5 | import snapcraft 6 | from snapcraft.plugins import dump 7 | 8 | extras = [ "xcolor", "tcolorbox", "pgf", "ms", "environ", "pgfplots", 9 | "metalogo", "trimspaces", "etoolbox" ] 10 | 11 | class TexLivePlugin(snapcraft.plugins.dump.DumpPlugin): 12 | 13 | def build(self): 14 | super(dump.DumpPlugin, self).build() 15 | 16 | # Install TexLive with the standard installer 17 | env = self._build_environment() 18 | p1 = Popen(['echo', '-n', 'I'], env=env, stdout=PIPE) 19 | p2 = Popen(['{}/install-tl'.format(self.builddir), '-portable', '-scheme', 'basic'], env=env, stdin=p1.stdout, stdout=PIPE) 20 | output = p2.communicate()[0] 21 | self.run(['{}/texlive/bin/x86_64-linux/tlmgr'.format(self.installdir), 22 | 'install'] + extras, env=env) 23 | 24 | def _build_environment(self): 25 | env = os.environ.copy() 26 | env['TEXLIVE_INSTALL_PREFIX'] = os.path.join(self.installdir, 'texlive') 27 | return env 28 | -------------------------------------------------------------------------------- /matplotlib/past/tests/color_cycle_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demo of custom color-cycle settings to control colors for multi-line plots. 3 | 4 | This example demonstrates two different APIs: 5 | 6 | 1. Setting the default rc-parameter specifying the color cycle. 7 | This affects all subsequent plots. 8 | 2. Setting the color cycle for a specific axes. This only affects a single 9 | axes. 10 | """ 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | x = np.linspace(0, 2 * np.pi) 15 | offsets = np.linspace(0, 2*np.pi, 4, endpoint=False) 16 | # Create array with shifted-sine curve along each column 17 | yy = np.transpose([np.sin(x + phi) for phi in offsets]) 18 | 19 | plt.rc('lines', linewidth=4) 20 | fig, (ax0, ax1) = plt.subplots(nrows=2) 21 | 22 | plt.rc('axes', color_cycle=['r', 'g', 'b', 'y']) 23 | ax0.plot(yy) 24 | ax0.set_title('Set default color cycle to rgby') 25 | 26 | ax1.set_color_cycle(['c', 'm', 'y', 'k']) 27 | ax1.plot(yy) 28 | ax1.set_title('Set axes color cycle to cmyk') 29 | 30 | # Tweak spacing between subplots to prevent labels from overlapping 31 | plt.subplots_adjust(hspace=0.3) 32 | 33 | -------------------------------------------------------------------------------- /matplotlib/past/tests/barchart_demo.py: -------------------------------------------------------------------------------- 1 | # a bar plot with errorbars 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | N = 5 6 | menMeans = (20, 35, 30, 35, 27) 7 | menStd = (2, 3, 4, 1, 2) 8 | 9 | ind = np.arange(N) # the x locations for the groups 10 | width = 0.35 # the width of the bars 11 | 12 | fig, ax = plt.subplots() 13 | rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd) 14 | 15 | womenMeans = (25, 32, 34, 20, 25) 16 | womenStd = (3, 5, 2, 3, 3) 17 | rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd) 18 | 19 | # add some text for labels, title and axes ticks 20 | ax.set_ylabel('Scores') 21 | ax.set_title('Scores by group and gender') 22 | ax.set_xticks(ind+width) 23 | ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') ) 24 | 25 | ax.legend( (rects1[0], rects2[0]), ('Men', 'Women') ) 26 | 27 | def autolabel(rects): 28 | # attach some text labels 29 | for rect in rects: 30 | height = rect.get_height() 31 | ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height), 32 | ha='center', va='bottom') 33 | 34 | autolabel(rects1) 35 | autolabel(rects2) 36 | -------------------------------------------------------------------------------- /matplotlib/tests/histogram_path_demo.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import matplotlib.patches as patches 5 | import matplotlib.path as path 6 | from matplotlib import use 7 | use('module://backend_ipe') 8 | 9 | fig, ax = plt.subplots() 10 | 11 | # histogram our data with numpy 12 | data = np.random.randn(1000) 13 | n, bins = np.histogram(data, 50) 14 | 15 | # get the corners of the rectangles for the histogram 16 | left = np.array(bins[:-1]) 17 | right = np.array(bins[1:]) 18 | bottom = np.zeros(len(left)) 19 | top = bottom + n 20 | 21 | 22 | # we need a (numrects x numsides x 2) numpy array for the path helper 23 | # function to build a compound path 24 | XY = np.array([[left, left, right, right], [bottom, top, top, bottom]]).T 25 | 26 | # get the Path object 27 | barpath = path.Path.make_compound_path_from_polys(XY) 28 | 29 | # make a patch out of it 30 | patch = patches.PathPatch(barpath, facecolor='blue', edgecolor='gray', 31 | alpha=0.8) 32 | ax.add_patch(patch) 33 | 34 | # update the view limits 35 | ax.set_xlim(left[0], right[-1]) 36 | ax.set_ylim(bottom.min(), top.max()) 37 | 38 | # plt.show() 39 | plt.savefig('histogram_path_demo.ipe') 40 | -------------------------------------------------------------------------------- /matplotlib/tests/barchart_demo.py: -------------------------------------------------------------------------------- 1 | # a bar plot with errorbars 2 | from matplotlib import pyplot as plt, use 3 | import numpy as np 4 | 5 | 6 | N = 5 7 | menMeans = (20, 35, 30, 35, 27) 8 | menStd = (2, 3, 4, 1, 2) 9 | 10 | ind = np.arange(N) # the x locations for the groups 11 | width = 0.35 # the width of the bars 12 | 13 | 14 | use('module://backend_ipe') 15 | 16 | fig, ax = plt.subplots() 17 | rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd) 18 | 19 | womenMeans = (25, 32, 34, 20, 25) 20 | womenStd = (3, 5, 2, 3, 3) 21 | rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd) 22 | 23 | # add some text for labels, title and axes ticks 24 | ax.set_ylabel('Scores') 25 | ax.set_title('Scores by group and gender') 26 | ax.set_xticks(ind+width) 27 | ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5')) 28 | 29 | ax.legend((rects1[0], rects2[0]), ('Men', 'Women')) 30 | 31 | 32 | def autolabel(rects): 33 | # attach some text labels 34 | for rect in rects: 35 | height = rect.get_height() 36 | ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, 37 | '%d' % int(height), ha='center', va='bottom') 38 | 39 | 40 | autolabel(rects1) 41 | autolabel(rects2) 42 | 43 | plt.savefig('barchart_demo.ipe', format='ipe') 44 | -------------------------------------------------------------------------------- /pdftoipe/Makefile: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------- 2 | # Makefile for pdftoipe 3 | # -------------------------------------------------------------------- 4 | 5 | ifdef COMSPEC 6 | # compiling on Windows? 7 | CPPFLAGS += -I/minglibs/include/poppler 8 | LIBS += -L/minglibs/lib -lpoppler 9 | LDFLAGS += -static 10 | TARGET = pdftoipe.exe 11 | else ifdef IPECROSS 12 | # cross-compiling for Windows? 13 | CXX=$(IPECROSS)-w64-mingw32-g++ 14 | CPPFLAGS += -I/sw/mingwlibs-$(IPECROSS)/include/poppler 15 | LIBS += -L/sw/mingwlibs-$(IPECROSS)/lib -lpoppler 16 | LDFLAGS += -static 17 | TARGET = pdftoipe.exe 18 | else 19 | POPPLER_CFLAGS ?= $(shell pkg-config --cflags poppler) 20 | POPPLER_LIBS ?= $(shell pkg-config --libs poppler) 21 | CPPFLAGS += $(POPPLER_CFLAGS) 22 | LIBS += $(POPPLER_LIBS) 23 | TARGET = pdftoipe 24 | endif 25 | 26 | CXXFLAGS += -Wno-write-strings -std=c++20 27 | 28 | all: $(TARGET) 29 | 30 | objects = parseargs.o xmloutputdev.o pdftoipe.o 31 | 32 | $(TARGET): $(objects) 33 | $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) 34 | 35 | clean: 36 | @-rm -f $(objects) $(TARGET) 37 | 38 | xmloutputdev.o: xmloutputdev.h 39 | pdftoipe.o: xmloutputdev.h parseargs.h 40 | parseargs.o: parseargs.h 41 | 42 | # -------------------------------------------------------------------- 43 | -------------------------------------------------------------------------------- /ipepython/test.py: -------------------------------------------------------------------------------- 1 | # 2 | # Access Ipe document from Python 3 | # 4 | 5 | import sys, os 6 | import math 7 | 8 | assert sys.hexversion >= 0x3060000 9 | 10 | import ipe 11 | 12 | print("Ipe configuration: ", ipe.config.latexdir, ipe.config.version) 13 | 14 | print("Testing ipe.Vector and ipe.Matrix:") 15 | v1 = ipe.Vector() 16 | v2 = ipe.Vector(3, 2) 17 | v3 = ipe.Direction(math.pi/4.0) 18 | print(v1, v2, v3) 19 | print(v1 + v2, v2 + v3, v3 - v2) 20 | print(v2.len(), v3.len(), v2.angle(), v3.angle()) 21 | print(v2 == v1 + v2, v2 == v2 + v3) 22 | print("Dot products: ", v1 ^ v2, v2 ^ v3) 23 | print(3 * v2, v3 * 7) 24 | print(-v2, -v3) 25 | 26 | m1 = ipe.Matrix(1.0, 0, 0, 2.0, 5, 8) 27 | m2 = ipe.Matrix(1.0, 2, 3, -1.0, 0, 0) 28 | print(m1, m2) 29 | print(m1 * m2) 30 | print(m1 * v2, m1 * v3, m2 * v3) 31 | 32 | if len(sys.argv) == 2: 33 | ipename = sys.argv[1] 34 | else: 35 | ipename = "../poweripe/demo-presentation.ipe" 36 | 37 | doc = ipe.Document(ipename) 38 | print("Document has ", len(doc), "pages and ", doc.countTotalViews(), "views") 39 | 40 | props = doc.properties() 41 | print("Some document properties: ", props.title, props.created, props.creator) 42 | print("All document properties:") 43 | for k in props: 44 | print(" -", k, props[k]) 45 | 46 | for pageNo in range(1, len(doc) + 1): 47 | print("Page %d has %d objects" % (pageNo, len(doc[pageNo]))) 48 | -------------------------------------------------------------------------------- /obs/make-specs.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Produce ipe.dsc and ipe_x.y.z-d.debian.tar.xz 3 | # 4 | # To create a new version, update IPEVERS below and add a new entry in debian/changelog 5 | # Then run bash make-specs.sh, and upload the three files to build.opensuse.org 6 | 7 | IPEVERS="7.2.29" 8 | DEBVERS="1" 9 | 10 | SOURCES=ipe-$IPEVERS.tar.gz 11 | 12 | ORIGFILE=ipe_$IPEVERS.orig.tar.gz 13 | DEBFILE=ipe_$IPEVERS-${DEBVERS}.debian.tar.xz 14 | DSCFILE=ipe.dsc 15 | 16 | rm -f $ORIGFILE $DEBFILE $DSCFILE 17 | 18 | tar cJvf $DEBFILE debian 19 | cat < $DSCFILE 20 | Format: 3.0 (quilt) 21 | Source: ipe 22 | EOF 23 | 24 | echo "Version: $IPEVERS-$DEBVERS" >> $DSCFILE 25 | 26 | cat <> $DSCFILE 27 | Binary: ipe 28 | Maintainer: Otfried Cheong 29 | Architecture: any 30 | Homepage: http://ipe.otfried.org/ 31 | Build-Depends: sharutils, doxygen, debhelper (>= 9~), zlib1g-dev, qt6-base-dev, qt6-base-dev-tools, libfreetype6-dev, libcairo2-dev, libjpeg-dev, libpng-dev, liblua5.4-dev, libgsl-dev, libspiro-dev, libcurl4-openssl-dev, libfontconfig1-dev 32 | Files: 33 | EOF 34 | 35 | cp $SOURCES $ORIGFILE 36 | orig1=`md5sum $ORIGFILE | cut -d" " -f1` 37 | orig2=`stat --printf="%s" $ORIGFILE` 38 | deb1=`md5sum $DEBFILE | cut -d" " -f1` 39 | deb2=`stat --printf="%s" $DEBFILE` 40 | 41 | echo "" $orig1 $orig2 $ORIGFILE >> $DSCFILE 42 | echo "" $deb1 $deb2 $DEBFILE >> $DSCFILE 43 | -------------------------------------------------------------------------------- /matplotlib/past/tests/date_demo.py: -------------------------------------------------------------------------------- 1 | 2 | import datetime 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import matplotlib.dates as mdates 6 | import matplotlib.cbook as cbook 7 | 8 | years = mdates.YearLocator() # every year 9 | months = mdates.MonthLocator() # every month 10 | yearsFmt = mdates.DateFormatter('%Y') 11 | 12 | # load a numpy record array from yahoo csv data with fields date, 13 | # open, close, volume, adj_close from the mpl-data/example directory. 14 | # The record array stores python datetime.date as an object array in 15 | # the date column 16 | datafile = cbook.get_sample_data('goog.npy') 17 | r = np.load(datafile).view(np.recarray) 18 | 19 | fig, ax = plt.subplots() 20 | ax.plot(r.date, r.adj_close) 21 | 22 | 23 | # format the ticks 24 | ax.xaxis.set_major_locator(years) 25 | ax.xaxis.set_major_formatter(yearsFmt) 26 | ax.xaxis.set_minor_locator(months) 27 | 28 | datemin = datetime.date(r.date.min().year, 1, 1) 29 | datemax = datetime.date(r.date.max().year+1, 1, 1) 30 | ax.set_xlim(datemin, datemax) 31 | 32 | # format the coords message box 33 | def price(x): return '$%1.2f'%x 34 | ax.format_xdata = mdates.DateFormatter('%Y-%m-%d') 35 | ax.format_ydata = price 36 | ax.grid(True) 37 | 38 | # rotates and right aligns the x labels, and moves the bottom of the 39 | # axes up to make room for them 40 | fig.autofmt_xdate() 41 | 42 | -------------------------------------------------------------------------------- /annotate/annotate.py: -------------------------------------------------------------------------------- 1 | # 2 | # Create an Ipe file including pages of given PDF document 3 | # 4 | 5 | import sys, os 6 | import PyPDF2 as pdf 7 | 8 | # -------------------------------------------------------------------- 9 | 10 | def create_ipe(pdffile): 11 | i = pdffile.rfind("/") 12 | if i >= 0: 13 | outfile = pdffile[i+1:] 14 | else: 15 | outfile = pdffile 16 | if outfile.endswith(".pdf"): 17 | outfile = outfile[:-4] 18 | 19 | outfile = "annotate-" + outfile + ".ipe" 20 | doc = pdf.PdfFileReader(pdffile) 21 | numPages = doc.numPages 22 | out = open(outfile, "w") 23 | out.write(""" 24 | \\usepackage{graphicx} 25 | 26 | 27 | 28 | """) 29 | for i in range(numPages): 30 | out.write(""" 31 | 32 | 33 | \includegraphics[page=%d]{%s} 34 | \n""" % (i+1, pdffile)) 35 | out.write("\n") 36 | out.close() 37 | os.system("ipescript update-styles %s" % outfile) 38 | 39 | # -------------------------------------------------------------------- 40 | 41 | if len(sys.argv) != 2: 42 | sys.stderr.write("Usage: python annotate.py \n") 43 | sys.exit(9) 44 | 45 | pdffile = sys.argv[1] 46 | create_ipe(pdffile) 47 | 48 | # -------------------------------------------------------------------- 49 | -------------------------------------------------------------------------------- /svgtoipe/test_svg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Test svgtoipe.py on a few examples 5 | # 6 | # More tests: 7 | # SVG Test suite with PNG reference: https://www.w3.org/Graphics/SVG/Test/20110816/ 8 | # 9 | 10 | 11 | import os, sys, re 12 | import urllib.request 13 | 14 | assert sys.hexversion >= 0x3000000, "Please run using Python 3" 15 | 16 | ignore = set(["photos.svg", "videos.svg"]) 17 | 18 | def getSamples(): 19 | url = "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/" 20 | req = urllib.request.Request(url) 21 | f = urllib.request.urlopen(req) 22 | index = f.read() 23 | fpat = re.compile(b'href="([-_a-zA-Z0-9]+\\.svg)"') 24 | for m in fpat.finditer(index): 25 | fname = m.group(1).decode("UTF-8") 26 | if fname in ignore: 27 | continue 28 | if os.path.exists("test/" + fname): 29 | continue 30 | sys.stderr.write("Downloading '%s'\n" % fname) 31 | req1 = urllib.request.Request(url + fname) 32 | ex = urllib.request.urlopen(req1).read() 33 | out = open("test/" + fname, "wb") 34 | out.write(ex) 35 | out.close() 36 | 37 | def testSamples(): 38 | files = os.listdir("./test") 39 | for f in files: 40 | if not f.endswith(".svg"): 41 | continue 42 | status = os.system("python3 svgtoipe.py test/%s 2> test/results-%s.txt" % (f, f)) 43 | if status != 0: 44 | sys.stderr.write("Error converting '%s'\n" % f) 45 | else: 46 | sys.stderr.write("Converted '%s'\n" % f) 47 | 48 | if __name__ == "__main__": 49 | getSamples() 50 | testSamples() 51 | -------------------------------------------------------------------------------- /svgtoipe/svgtoipe.1: -------------------------------------------------------------------------------- 1 | .TH SVGTOIPE "1" "April 2015" "Ipe" "User Commands" 2 | 3 | .SH NAME 4 | svgtoipe \- Convert a SVG file to Ipe 7 format 5 | 6 | .SH SYNOPSIS 7 | .B svgtoipe 8 | \fI[\-h] [\-c] figure.svg [figure.ipe] \fR 9 | 10 | .SH DESCRIPTION 11 | \fBsvgtoipe\fR converts a SVG file to an XML file understood by Ipe 12 | version 7. 13 | .PP 14 | If the output filename is not specified, it will be derived 15 | either by replacing \fI.ipe\fR at the end of the input filename with 16 | \fI.svg\fR, or by appending \fI.ipe\fR if the input filename does not 17 | end with with \fI.svg\fR. 18 | 19 | If either input or output filename is '\-\-', then stdin, resp. stdout 20 | is used to read or write data. 21 | .TP 22 | \-h 23 | display a short help text 24 | .TP 25 | \-c 26 | operate in clipboard mode. Data is output as ipe clipboard content. 27 | This allows pasting svg data from inkscape to ipe: 28 | (1) Copy elements Inkscape to clipboard, 29 | (2) run: 'xsel | ./svgtoipe.py -c -- | xsel -i', 30 | (3) paste clipboard content into ipe. 31 | 32 | .SH Supported SVG Features 33 | 34 | The following SVG elements are converted: path, image, rect, circle, ellipse, 35 | line, polygon, and polyline 36 | 37 | The following SVG elements are converted: group, clipPath, linearGradient, 38 | andradialGradient 39 | 40 | Image conversion is only supported if \fIpython-imaging\fR is available. Text 41 | is only converted, if it has coordinates specified as attribute of the svg text 42 | element. 43 | 44 | .SH AUTHOR 45 | Otfried Cheong 46 | Christian Kapeller 47 | 48 | .SH "SEE ALSO" 49 | \fBipe\fR(1) 50 | -------------------------------------------------------------------------------- /matplotlib/tests/clip_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.cm as cm 3 | import matplotlib.mlab as mlab 4 | import matplotlib.pyplot as plt 5 | from matplotlib.path import Path 6 | from matplotlib.patches import PathPatch 7 | from matplotlib import use 8 | use("module://backend_ipe") 9 | 10 | 11 | def bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, 12 | mux=0.0, muy=0.0, sigmaxy=0.0): 13 | """ 14 | Bivariate Gaussian distribution for equal shape *X*, *Y*. 15 | 16 | See `bivariate normal 17 | `_ 18 | at mathworld. 19 | """ 20 | Xmu = X-mux 21 | Ymu = Y-muy 22 | 23 | rho = sigmaxy/(sigmax*sigmay) 24 | z = Xmu**2/sigmax**2 + Ymu**2/sigmay**2 - 2*rho*Xmu*Ymu/(sigmax*sigmay) 25 | denom = 2*np.pi*sigmax*sigmay*np.sqrt(1-rho**2) 26 | return np.exp(-z/(2*(1-rho**2))) / denom 27 | 28 | 29 | delta = 0.025 30 | x = y = np.arange(-3.0, 3.0, delta) 31 | X, Y = np.meshgrid(x, y) 32 | Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 33 | Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 34 | Z = Z2-Z1 # difference of Gaussians 35 | 36 | path = Path([[0, 1], [1, 0], [0, -1], [-1, 0], [0, 1]]) 37 | patch = PathPatch(path, facecolor='none') 38 | plt.gca().add_patch(patch) 39 | 40 | im = plt.imshow(Z, interpolation='bilinear', cmap=cm.gray, 41 | origin='lower', extent=[-3, 3, -3, 3], 42 | clip_path=patch, clip_on=True) 43 | im.set_clip_path(patch) 44 | 45 | plt.savefig('clip_test.ipe', format='ipe') 46 | -------------------------------------------------------------------------------- /matplotlib/tests/color_cycle_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demo of custom color-cycle settings to control colors for multi-line plots. 3 | 4 | This example demonstrates two different APIs: 5 | 6 | 1. Setting the default rc-parameter specifying the color cycle. 7 | This affects all subsequent plots. 8 | 2. Setting the color cycle for a specific axes. This only affects a single 9 | axes. 10 | """ 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | from cycler import cycler 14 | from matplotlib import use 15 | use('module://backend_ipe') 16 | 17 | x = np.linspace(0, 2 * np.pi) 18 | offsets = np.linspace(0, 2*np.pi, 4, endpoint=False) 19 | # Create array with shifted-sine curve along each column 20 | yy = np.transpose([np.sin(x + phi) for phi in offsets]) 21 | 22 | 23 | default_cycler = (cycler(color=['r', 'g', 'b', 'y']) + 24 | cycler(linestyle=['-', '--', ':', '-.'])) 25 | # plt.rc('axes', color_cycle=['r', 'g', 'b', 'y']) 26 | plt.rc('lines', linewidth=4) 27 | plt.rc('axes', prop_cycle=default_cycler) 28 | fig, (ax0, ax1) = plt.subplots(nrows=2) 29 | ax0.plot(yy) 30 | ax0.set_title('Set default color cycle to rgby') 31 | custom_cycler = (cycler(color=['c', 'm', 'y', 'k']) + 32 | cycler(lw=[1, 2, 3, 4])) 33 | ax1.set_prop_cycle(custom_cycler) 34 | # ax1.set_color_cycle(['c', 'm', 'y', 'k']) 35 | ax1.plot(yy) 36 | ax1.set_title('Set axes color cycle to cmyk') 37 | 38 | # Tweak spacing between subplots to prevent labels from overlapping 39 | plt.subplots_adjust(hspace=0.3) 40 | 41 | # plt.show() 42 | plt.savefig('color_cycle_demo.ipe') 43 | -------------------------------------------------------------------------------- /figtoipe/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Figtoipe 3 | ======== 4 | 5 | This is Figtoipe, a program that reads FIG files (as generated by 6 | xfig) and generates an XML file readable by Ipe. 7 | 8 | Compile by saying 9 | make 10 | 11 | A changelog is in the source file "figtoipe.cpp". 12 | 13 | Before reporting a bug, check that you have the latest version, and 14 | check that it is not yet mentioned in the FAQ on the Ipe webpage. 15 | 16 | You can report bugs on the issue tracking system at 17 | "https://github.com/otfried/ipe-tools/issues". 18 | 19 | Check the existing reports to see whether your bug has already been 20 | reported. Please do not send bug reports directly to us (the first 21 | thing we would do with the report is to enter it into the bug tracking 22 | system). 23 | 24 | Suggestions for features, or random comments on Figtoipe can be sent 25 | to the Ipe discussion mailing list at . You can 26 | also send suggestions or comments directly to us by Email, but you 27 | should then not expect a reply. 28 | 29 | Alexander Bürger, acfb@users.sourceforge.net 30 | Otfried Cheong, ipe@otfried.org 31 | 32 | Ipe webpage: http://ipe.otfried.org 33 | 34 | -------------------------------------------------------------------- 35 | 36 | figtoipe comes with ABSOLUTELY NO WARRANTY. It is free software; you 37 | can redistribute it and/or modify it under the terms of the GNU 38 | General Public License as published by the Free Software Foundation; 39 | either version 2 of the License, or (at your option) any later 40 | version. 41 | 42 | See the file gpl.txt for details. 43 | -------------------------------------------------------------------------------- /matplotlib/past/run_test.py: -------------------------------------------------------------------------------- 1 | # 2 | # Run all the tests in tests subdirectory 3 | # and save plots in ipe and svg format 4 | # 5 | from __future__ import division, print_function, unicode_literals 6 | 7 | import os, sys 8 | 9 | def fix_file(f): 10 | data = open("tests/%s" % f, "r").readlines() 11 | os.rename("tests/%s" % f, "tests/%s.bak" % f) 12 | out = open("tests/%s" % f, "w") 13 | for l in data: 14 | ll = l.strip() 15 | if ll == "import matplotlib as mpl": continue 16 | if ll == "print mpl.__file__": continue 17 | if ll == "mpl.use('module://backend_ipe')": continue 18 | if ll == "#mpl.use('module://backend_ipe')": continue 19 | if ll == "#plt.show()" or ll == "plt.show()": continue 20 | if ll[:12] == "#plt.savefig": continue 21 | if ll[:11] == "plt.savefig": continue 22 | out.write(l) 23 | out.close() 24 | 25 | def runall(form): 26 | tests = [f[:-3] for f in os.listdir("tests") if f[-3:] == ".py"] 27 | for f in tests: 28 | # doesn't work on my matplotlib version 29 | if f == "power_norm_demo": continue 30 | run(form, f) 31 | 32 | def run(form, f): 33 | sys.stderr.write("# %s\n" % f) 34 | t = open("tmp.py", "w") 35 | t.write("""# %s 36 | import matplotlib as mpl 37 | """ % f) 38 | if form=="ipe": 39 | t.write("mpl.use('module://backend_ipe')\n") 40 | t.write(open("tests/%s.py" % f, "r").read()) 41 | t.write("plt.savefig('out/%s.%s', format='%s')\n" % (f, form, form)) 42 | t.close() 43 | os.system("python tmp.py") 44 | 45 | if len(sys.argv) != 3: 46 | sys.stderr.write("Usage: run_test.py \n") 47 | sys.exit(9) 48 | 49 | form = sys.argv[1] 50 | test = sys.argv[2] 51 | if test == 'all': 52 | runall(form) 53 | else: 54 | run(form, test) 55 | 56 | -------------------------------------------------------------------------------- /obs/debian/control: -------------------------------------------------------------------------------- 1 | Source: ipe 2 | Maintainer: Otfried Cheong 3 | Section: graphics 4 | Priority: optional 5 | Build-Depends: sharutils, 6 | debhelper (>= 9~), 7 | zlib1g-dev, 8 | qt6-base-dev, 9 | qt6-base-dev-tools, 10 | libfreetype6-dev, 11 | libcairo2-dev, 12 | libfontconfig1-dev, 13 | libjpeg-dev, 14 | libpng-dev, 15 | liblua5.4-dev, 16 | libgsl-dev, 17 | libspiro-dev, 18 | libcurl4-openssl-dev 19 | Homepage: http://ipe.otfried.org/ 20 | 21 | Package: ipe 22 | Architecture: any 23 | Depends: ${misc:Depends}, 24 | ${shlibs:Depends}, 25 | libqt6svg6 26 | Description: The Ipe extensible drawing editor 27 | Ipe is a drawing editor for creating figures in PDF format. It 28 | supports making small figures for inclusion into LaTeX-documents as 29 | well as making multi-page PDF presentations. 30 | Ipe's main features are: 31 | * Entry of text as LaTeX source code. This makes it easy to enter 32 | mathematical expressions, and to reuse the LaTeX-macros of the main 33 | document. In the display text is displayed as it will appear in 34 | the figure. 35 | * Produces pure PDF, including the text. Ipe converts the LaTeX-source 36 | to PDF when the file is saved. 37 | * It is easy to align objects with respect to each other (for 38 | instance, to place a point on the intersection of two lines, or to 39 | draw a circle through three given points) using various snapping 40 | modes. 41 | * Users can provide ipelets (Ipe plug-ins) to add functionality to 42 | Ipe. This way, Ipe can be extended for each task at hand. 43 | -------------------------------------------------------------------------------- /matplotlib/past/tests/donut_demo.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.path as mpath 4 | import matplotlib.patches as mpatches 5 | import matplotlib.pyplot as plt 6 | 7 | def wise(v): 8 | if v == 1: 9 | return "CCW" 10 | else: 11 | return "CW" 12 | 13 | def make_circle(r): 14 | t = np.arange(0, np.pi * 2.0, 0.01) 15 | t = t.reshape((len(t), 1)) 16 | x = r * np.cos(t) 17 | y = r * np.sin(t) 18 | return np.hstack((x, y)) 19 | 20 | Path = mpath.Path 21 | 22 | fig, ax = plt.subplots() 23 | 24 | inside_vertices = make_circle(0.5) 25 | outside_vertices = make_circle(1.0) 26 | codes = np.ones(len(inside_vertices), dtype=mpath.Path.code_type) * mpath.Path.LINETO 27 | codes[0] = mpath.Path.MOVETO 28 | 29 | for i, (inside, outside) in enumerate(((1, 1), (1, -1), (-1, 1), (-1, -1))): 30 | # Concatenate the inside and outside subpaths together, changing their 31 | # order as needed 32 | vertices = np.concatenate((outside_vertices[::outside], 33 | inside_vertices[::inside])) 34 | # Shift the path 35 | vertices[:, 0] += i * 2.5 36 | # The codes will be all "LINETO" commands, except for "MOVETO"s at the 37 | # beginning of each subpath 38 | all_codes = np.concatenate((codes, codes)) 39 | # Create the Path object 40 | path = mpath.Path(vertices, all_codes) 41 | # Add plot it 42 | patch = mpatches.PathPatch(path, facecolor='#885500', edgecolor='black') 43 | ax.add_patch(patch) 44 | 45 | ax.annotate("Outside %s,\nInside %s" % (wise(outside), wise(inside)), 46 | (i * 2.5, -1.5), va="top", ha="center") 47 | 48 | ax.set_xlim(-2,10) 49 | ax.set_ylim(-3,2) 50 | ax.set_title('Mmm, donuts!') 51 | ax.set_aspect(1.0) 52 | 53 | -------------------------------------------------------------------------------- /appimage/Ipe.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | ​ 3 | ​ 4 | ​ org.otfried.ipe 5 | ​ FSFAP 6 | ​ GPL-3.0+ 7 | ​ Ipe 8 | ​ The Ipe extensible drawing editor 9 | ​ 10 | ​ 11 |

Ipe is a drawing editor for creating figures in PDF format. It supports making small figures for inclusion 12 | into \LaTeX{}-documents as well as making multi-page PDF presentations.

13 | 14 |

Ipe's main features are:

15 |
    16 |
  • Entry of text as LaTeX source code. This makes it easy to 17 | enter mathematical expressions, and to reuse the LaTeX-macros of 18 | the main document. In the display text is displayed as it will 19 | appear in the figure.
  • 20 |
  • Produces pure PDF, including the text. Ipe converts 21 | the LaTeX-source to PDF when the file is saved.
  • 22 |
  • It is easy to align objects with respect to each other (for 23 | instance, to place a point on the intersection of two lines, or to 24 | draw a circle through three given points) using various snapping 25 | modes.
  • 26 |
  • Users can provide ipelets (Ipe plug-ins) to add 27 | functionality to Ipe. This way, Ipe can be extended for each task 28 | at hand.
  • 29 |
30 | ​
31 | ​ 32 | ​ Ipe.desktop 33 | ​ 34 | http://ipe.otfried.org 35 | 36 | Otfried Cheong 37 | ​ 38 | ​ 39 | ​ 40 | ​ 41 | ​
42 | -------------------------------------------------------------------------------- /matplotlib/tests/donut_demo.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.path as mpath 3 | import matplotlib.patches as mpatches 4 | import matplotlib.pyplot as plt 5 | from matplotlib import use 6 | use('module://backend_ipe') 7 | 8 | 9 | def wise(v): 10 | if v == 1: 11 | return "CCW" 12 | else: 13 | return "CW" 14 | 15 | 16 | def make_circle(r): 17 | t = np.arange(0, np.pi * 2.0, 0.01) 18 | t = t.reshape((len(t), 1)) 19 | x = r * np.cos(t) 20 | y = r * np.sin(t) 21 | return np.hstack((x, y)) 22 | 23 | 24 | Path = mpath.Path 25 | fig, ax = plt.subplots() 26 | 27 | inside_vertices = make_circle(0.5) 28 | outside_vertices = make_circle(1.0) 29 | codes = np.ones(len(inside_vertices), 30 | dtype=mpath.Path.code_type) * mpath.Path.LINETO 31 | codes[0] = mpath.Path.MOVETO 32 | 33 | for i, (inside, outside) in enumerate(((1, 1), (1, -1), (-1, 1), (-1, -1))): 34 | # Concatenate the inside and outside subpaths together, changing their 35 | # order as needed 36 | vertices = np.concatenate((outside_vertices[::outside], 37 | inside_vertices[::inside])) 38 | # Shift the path 39 | vertices[:, 0] += i * 2.5 40 | # The codes will be all "LINETO" commands, except for "MOVETO"s at the 41 | # beginning of each subpath 42 | all_codes = np.concatenate((codes, codes)) 43 | # Create the Path object 44 | path = mpath.Path(vertices, all_codes) 45 | # Add plot it 46 | patch = mpatches.PathPatch(path, facecolor='#885500', edgecolor='black') 47 | ax.add_patch(patch) 48 | 49 | ax.annotate("Outside %s,\nInside %s" % (wise(outside), wise(inside)), 50 | (i * 2.5, -1.5), va="top", ha="center") 51 | 52 | ax.set_xlim(-2, 10) 53 | ax.set_ylim(-3, 2) 54 | ax.set_title('Mmm, donuts!') 55 | ax.set_aspect(1.0) 56 | 57 | plt.savefig('donut_demo.ipe') 58 | -------------------------------------------------------------------------------- /ipepython/readme.md: -------------------------------------------------------------------------------- 1 | # Ipe Python module 2 | 3 | This is an extension module that will let you read and write Ipe 4 | documents from Python 3. 5 | 6 | It makes the Ipe Lua-bindings available using a Python-Lua bridge 7 | based on code written by [Gustavo 8 | Niemeyer](http://labix.org/lunatic-python). 9 | 10 | ## Installation 11 | 12 | You'll need to fill in the arguments to find the Lua and Ipe header 13 | files and library in `setup.py`. Then say 14 | ``` 15 | python3 setup.py build 16 | python3 setup.py install --user 17 | ``` 18 | 19 | ## Documentation 20 | 21 | After loading the module: 22 | 23 | ``` 24 | import ipe 25 | ``` 26 | 27 | you can use the functions documented in the [Lua 28 | bindings](http://ipe.otfried.org/manual/lua.html). For instance, load 29 | an Ipe document by saying: 30 | 31 | ``` 32 | doc = ipe.Document("filename.pdf") 33 | ``` 34 | 35 | Have a look at `test.py` for an example. 36 | 37 | 38 | **Tables:** Several methods in the module return *Lua tables*. These 39 | are similar to Python dictionaries, but are a distinct type. 40 | 41 | For instance, 42 | 43 | ``` 44 | props = doc.properties() 45 | ``` 46 | 47 | will set `props` to be a table with keys such as `author`, `title`, 48 | `created`, etc. 49 | 50 | You can access the elements of a table using either 51 | attribute syntax (`props.title`) or dictionary syntax 52 | (`props['title']`). You can also can iterate over the elements of a 53 | table in a `for` loop: 54 | 55 | ``` 56 | for k in props: 57 | print(k, props[k]) 58 | ``` 59 | 60 | **Sequences:** A document is a sequence of pages, a page is a sequence 61 | of graphical objects. In Lua, indices **start with one**, not zero! 62 | You can use Python's `len` function to determine the length of a 63 | sequence. For instance, loop over the pages of a document like this: 64 | 65 | ``` 66 | for pageNo in range(1, len(doc) + 1): 67 | print("Page %d has %d objects" % (pageNo, len(doc[pageNo]))) 68 | ``` 69 | 70 | **Iterators:** The Lua documentation shows loops using 71 | `page:objects()` and `document:pages()`. This does not work from 72 | Python. You should use a loop over the indices instead. 73 | -------------------------------------------------------------------------------- /appimage/README.md: -------------------------------------------------------------------------------- 1 | # Ipe AppImage recipe 2 | 3 | This is a recipe for building an [AppImage](http://appimage.org/) for 4 | Ipe, based on the [fantastic work of Thomas 5 | Leitz](https://github.com/unruhschuh/Ipe.AppImage) - I only tinkered 6 | with a few details and added the Voronoi ipelet and pdftoipe. 7 | 8 | Ipe requires `pdflatex` to be installed in order to render text 9 | elements. It is not included in the AppImage so you need to have a 10 | LaTeX distribution installed on your system. You can find informations 11 | about LaTeX and how to install it at 12 | [www.tug.org](https://www.tug.org/). 13 | 14 | 15 | ## Download 16 | 17 | * [Download](https://bintray.com/otfried/generic/ipe#files/ipe) the 18 | latest AppImage for Ipe 19 | 20 | * Make the AppImage executable, e.g. in the terminal run 21 | `chmod a+x ipe-x.y.z-x86_64.AppImage` 22 | 23 | 24 | ## How to use the Ipe AppImage 25 | 26 | * To start Ipe, just click on the AppImage file. 27 | 28 | * You can also start Ipe from the command line by executing the AppImage: 29 | ``` 30 | $ ./ipe-7.2.6-x86_64.AppImage 31 | ``` 32 | 33 | * If you want to use the Ipe command line tools, such as `ipetoipe`, `iperender`, `ipescript`, just prefix the command with the AppImage: 34 | ``` 35 | $ ./ipe-7.2.6-x86_64.AppImage ipetoipe -pdf ~/test.ipe 36 | ``` 37 | 38 | * If you want to start Ipe with a command line argument, proceed as for the tools: 39 | ``` 40 | $ ./ipe-7.2.6-x86_64.AppImage ipe -sheet presentation ~/mytalk.pdf 41 | ``` 42 | 43 | Note that you will have to use **absolute filenames** in the arguments 44 | to the command line tools, because the AppImage changes directory 45 | before executing the code. 46 | 47 | 48 | ## How to create an AppImage for Ipe 49 | 50 | The AppImage for Ipe is created inside a fresh installation of CentOS 51 | 6.7. In order to build the AppImage follow these steps 52 | 53 | * Install CentOS 6.7 either on a PC or inside VirtualBox or any other 54 | virtualization program. 55 | 56 | * Start the Terminal and run `git clone https://github.com/otfried/ipe-tools` 57 | 58 | * Change directory with `cd ipe-tools/appimage` 59 | 60 | * Download and compile the needed tools and libraries with 61 | `./setup.sh`. 62 | 63 | * Start Ipe compilation and packaging process with `./recipe.sh`. 64 | This creates `ipe-7.x.y-x86_64.AppImage` inside the current directory. 65 | 66 | -------------------------------------------------------------------------------- /matplotlib/past/tests/colormaps_reference.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | cmaps = [('Sequential', ['Blues', 'BuGn', 'BuPu', 7 | 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 8 | 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 9 | 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), 10 | ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', 11 | 'gist_heat', 'gray', 'hot', 'pink', 12 | 'spring', 'summer', 'winter']), 13 | ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 14 | 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', 15 | 'seismic']), 16 | ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', 17 | 'Pastel2', 'Set1', 'Set2', 'Set3']), 18 | ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', 19 | 'brg', 'CMRmap', 'cubehelix', 20 | 'gnuplot', 'gnuplot2', 'gist_ncar', 21 | # 'nipy_spectral', 'jet', 'rainbow', 22 | 'jet', 'rainbow', 'gist_rainbow', 23 | 'hsv', 'flag', 'prism'])] 24 | 25 | 26 | nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) 27 | gradient = np.linspace(0, 1, 256) 28 | gradient = np.vstack((gradient, gradient)) 29 | 30 | def plot_color_gradients(cmap_category, cmap_list): 31 | fig, axes = plt.subplots(nrows=nrows) 32 | fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) 33 | axes[0].set_title(cmap_category + ' colormaps', fontsize=14) 34 | 35 | for ax, name in zip(axes, cmap_list): 36 | ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) 37 | pos = list(ax.get_position().bounds) 38 | x_text = pos[0] - 0.01 39 | y_text = pos[1] + pos[3]/2. 40 | fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) 41 | 42 | # Turn off *all* ticks & spines, not just the ones with colormaps. 43 | for ax in axes: 44 | ax.set_axis_off() 45 | 46 | for cmap_category, cmap_list in cmaps: 47 | plot_color_gradients(cmap_category, cmap_list) 48 | 49 | 50 | -------------------------------------------------------------------------------- /matplotlib/past/tests/line_styles_reference.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | cmaps = [('Sequential', ['Blues', 'BuGn', 'BuPu', 7 | 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 8 | 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 9 | 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), 10 | ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', 11 | 'gist_heat', 'gray', 'hot', 'pink', 12 | 'spring', 'summer', 'winter']), 13 | ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 14 | 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', 15 | 'seismic']), 16 | ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', 17 | 'Pastel2', 'Set1', 'Set2', 'Set3']), 18 | ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', 19 | 'brg', 'CMRmap', 'cubehelix', 20 | 'gnuplot', 'gnuplot2', 'gist_ncar', 21 | # 'nipy_spectral', 'jet', 'rainbow', 22 | 'jet', 'rainbow', 23 | 'gist_rainbow', 'hsv', 'flag', 'prism'])] 24 | 25 | 26 | nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) 27 | gradient = np.linspace(0, 1, 256) 28 | gradient = np.vstack((gradient, gradient)) 29 | 30 | def plot_color_gradients(cmap_category, cmap_list): 31 | fig, axes = plt.subplots(nrows=nrows) 32 | fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) 33 | axes[0].set_title(cmap_category + ' colormaps', fontsize=14) 34 | 35 | for ax, name in zip(axes, cmap_list): 36 | ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) 37 | pos = list(ax.get_position().bounds) 38 | x_text = pos[0] - 0.01 39 | y_text = pos[1] + pos[3]/2. 40 | fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) 41 | 42 | # Turn off *all* ticks & spines, not just the ones with colormaps. 43 | for ax in axes: 44 | ax.set_axis_off() 45 | 46 | for cmap_category, cmap_list in cmaps: 47 | plot_color_gradients(cmap_category, cmap_list) 48 | 49 | 50 | -------------------------------------------------------------------------------- /pdftoipe/parseargs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * parseargs.h 3 | * 4 | * Command line argument parser. 5 | * 6 | * Copyright 1996-2003 Glyph & Cog, LLC 7 | */ 8 | 9 | //======================================================================== 10 | // 11 | // Modified under the Poppler project - http://poppler.freedesktop.org 12 | // 13 | // All changes made under the Poppler project to this file are licensed 14 | // under GPL version 2 or later 15 | // 16 | // Copyright (C) 2008 Albert Astals Cid 17 | // 18 | // To see a description of the changes please see the Changelog file that 19 | // came with your tarball or type make ChangeLog if you are building from git 20 | // 21 | //======================================================================== 22 | 23 | #ifndef PARSEARGS_H 24 | #define PARSEARGS_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /* 31 | * Argument kinds. 32 | */ 33 | typedef enum { 34 | argFlag, /* flag (present / not-present) */ 35 | /* [val: bool *] */ 36 | argInt, /* integer arg */ 37 | /* [val: int *] */ 38 | argFP, /* floating point arg */ 39 | /* [val: double *] */ 40 | argString, /* string arg */ 41 | /* [val: char *] */ 42 | /* dummy entries -- these show up in the usage listing only; */ 43 | /* useful for X args, for example */ 44 | argFlagDummy, 45 | argIntDummy, 46 | argFPDummy, 47 | argStringDummy 48 | } ArgKind; 49 | 50 | /* 51 | * Argument descriptor. 52 | */ 53 | typedef struct { 54 | char *arg; /* the command line switch */ 55 | ArgKind kind; /* kind of arg */ 56 | void *val; /* place to store value */ 57 | int size; /* for argString: size of string */ 58 | char *usage; /* usage string */ 59 | } ArgDesc; 60 | 61 | /* 62 | * Parse command line. Removes all args which are found in the arg 63 | * descriptor list . Stops parsing if "--" is found (and removes 64 | * it). Returns gFalse if there was an error. 65 | */ 66 | extern bool parseArgs(const ArgDesc *args, int *argc, char *argv[]); 67 | 68 | /* 69 | * Print usage message, based on arg descriptor list. 70 | */ 71 | extern void printUsage(char *program, char *otherArgs, const ArgDesc *args); 72 | 73 | /* 74 | * Check if a string is a valid integer or floating point number. 75 | */ 76 | extern bool isInt(char *s); 77 | extern bool isFP(char *s); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /matplotlib/tests/line_styles_reference.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from matplotlib import use 4 | use('module://backend_ipe') 5 | 6 | 7 | cmaps = [('Sequential', ['Blues', 'BuGn', 'BuPu', 8 | 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 9 | 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 10 | 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), 11 | ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', 12 | 'gist_heat', 'gray', 'hot', 'pink', 13 | 'spring', 'summer', 'winter']), 14 | ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 15 | 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', 16 | 'seismic']), 17 | ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', 18 | 'Pastel2', 'Set1', 'Set2', 'Set3']), 19 | ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', 20 | 'brg', 'CMRmap', 'cubehelix', 21 | 'gnuplot', 'gnuplot2', 'gist_ncar', 22 | # 'nipy_spectral', 'jet', 'rainbow', 23 | 'jet', 'rainbow', 24 | 'gist_rainbow', 'hsv', 'flag', 'prism'])] 25 | 26 | 27 | nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) 28 | gradient = np.linspace(0, 1, 256) 29 | gradient = np.vstack((gradient, gradient)) 30 | 31 | 32 | def plot_color_gradients(cmap_category, cmap_list): 33 | fig, axes = plt.subplots(nrows=nrows) 34 | fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) 35 | axes[0].set_title(cmap_category + ' colormaps', fontsize=14) 36 | 37 | for ax, name in zip(axes, cmap_list): 38 | ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) 39 | pos = list(ax.get_position().bounds) 40 | x_text = pos[0] - 0.01 41 | y_text = pos[1] + pos[3]/2. 42 | fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) 43 | 44 | # Turn off *all* ticks & spines, not just the ones with colormaps. 45 | for ax in axes: 46 | ax.set_axis_off() 47 | 48 | 49 | for cmap_category, cmap_list in cmaps: 50 | plot_color_gradients(cmap_category, cmap_list) 51 | plt.savefig(f'line_styles_reference_{cmap_category}.ipe') 52 | -------------------------------------------------------------------------------- /matplotlib/tests/colormaps_reference.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | from matplotlib import use 5 | use('module://backend_ipe') 6 | 7 | 8 | cmaps = [('Sequential', ['Blues', 'BuGn', 'BuPu', 9 | 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 10 | 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 11 | 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), 12 | ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', 13 | 'gist_heat', 'gray', 'hot', 'pink', 14 | 'spring', 'summer', 'winter']), 15 | ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 16 | 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', 17 | 'seismic']), 18 | ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', 19 | 'Pastel2', 'Set1', 'Set2', 'Set3']), 20 | ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', 21 | 'brg', 'CMRmap', 'cubehelix', 22 | 'gnuplot', 'gnuplot2', 'gist_ncar', 23 | # 'nipy_spectral', 'jet', 'rainbow', 24 | 'jet', 'rainbow', 'gist_rainbow', 25 | 'hsv', 'flag', 'prism'])] 26 | 27 | 28 | nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) 29 | gradient = np.linspace(0, 1, 256) 30 | gradient = np.vstack((gradient, gradient)) 31 | 32 | 33 | def plot_color_gradients(cmap_category, cmap_list): 34 | fig, axes = plt.subplots(nrows=nrows) 35 | fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) 36 | axes[0].set_title(cmap_category + ' colormaps', fontsize=14) 37 | 38 | for ax, name in zip(axes, cmap_list): 39 | ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) 40 | pos = list(ax.get_position().bounds) 41 | x_text = pos[0] - 0.01 42 | y_text = pos[1] + pos[3]/2. 43 | fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) 44 | 45 | # Turn off *all* ticks & spines, not just the ones with colormaps. 46 | for ax in axes: 47 | ax.set_axis_off() 48 | 49 | 50 | for cmap_category, cmap_list in cmaps: 51 | plot_color_gradients(cmap_category, cmap_list) 52 | plt.savefig(f'colormaps_reference_{cmap_category}.ipe') 53 | -------------------------------------------------------------------------------- /poweripe/readme.md: -------------------------------------------------------------------------------- 1 | # Poweripe 2 | 3 | Do you prefer to create your presentations in Ipe? But your 4 | bosses/colleagues/clients keep asking for Powerpoint files? 5 | 6 | Fear no more! Poweripe is a Python script that translates an Ipe 7 | presentation into a Powerpoint presentation. 8 | 9 | Poweripe requires Ipe 7.2.13 or later. 10 | 11 | ## Installation 12 | 13 | Poweripe requires some Python modules: 14 | 15 | 19 | 20 | 1. Install the 21 | [ipepython](https://github.com/otfried/ipe-tools/tree/master/ipepython) 22 | module. (This module is used to read Ipe files.) 23 | 24 | 2. Install the `python-pptx` module (a module for creating Powerpoint documents). 25 | Currently, you need to get my fork of this module, with added SVG 26 | support. You can find it at 27 | https://github.com/otfried/python-pptx. Make sure to get the **svg-pictures** branch! 28 | 29 | 36 | 37 | ## Usage 38 | 39 | You run Poweripe from the command line like this: 40 | ``` 41 | python3 poweripe.py --no-text presentation.pdf 42 | ``` 43 | The output will be stored in `presentation.pptx`. Alternatively, 44 | provide the `--output` option to select a different output file. 45 | 46 | In this simplest mode, Poweripe stores **all** the contents of the Ipe 47 | document, including all text, as *graphics* in the pptx output. There 48 | is both an SVG-version of this graphics, which gives high-quality 49 | vector output, and a lower-resolution bitmap as a fallback. Recent 50 | Powerpoint versions will display the SVG contents, but it seems that 51 | Libreoffice does not yet support SVG and shows the bitmap version 52 | instead. 53 | 54 | If you remove the `--no-text` option, Poweripe will convert all minipage 55 | text objects that contain only simple Latex markup into text objects that 56 | can be edited in the pptx file. 57 | 58 | With the `--latex` option, Poweripe will convert all minipage text 59 | objects. You will have to edit the resulting pptx file to make it useful. 60 | 61 | With the `--labels` option, Poweripe will also convert text in Label 62 | objects (not just minipage objects). 63 | 64 | Since the `python-pptx` library does not yet support making slides 65 | that build up incrementally, Poweripe currently converts only the 66 | **last view** of each page. 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ipe-tools 2 | ========= 3 | 4 | These are various tools and helper programs to be used 5 | with the Ipe drawing editor (http://ipe.otfried.org). 6 | 7 | 8 | svgtoipe.py 9 | ----------- 10 | 11 | A script that converts an SVG figure to Ipe format. It cannot handle 12 | all SVG features (many SVG features are not supported by Ipe anyway), 13 | but it works for gradients. 14 | 15 | 16 | ipepython 17 | --------- 18 | 19 | A Python 3 extension module that will let you open and work with Ipe 20 | documents from Python. 21 | 22 | 23 | Poweripe 24 | -------- 25 | 26 | Do you prefer to create your presentations in Ipe? But your 27 | bosses/colleagues/clients keep asking for Powerpoint files? 28 | 29 | Fear no more! Poweripe is a Python script that translates an Ipe 30 | presentation into a Powerpoint presentation. 31 | 32 | 33 | Matplotlib backend 34 | ------------------ 35 | 36 | Matplotlib is a Python module for scientific plotting. With this 37 | backend, you can create Ipe figures directly from matplotlib. 38 | 39 | 40 | pdftoipe 41 | -------- 42 | 43 | You can convert arbitrary Postscript or PDF files into Ipe documents, 44 | making them editable. The auxiliary program *pdftoipe* converts 45 | (pages from) a PDF file into an Ipe XML-file. (If your source is 46 | Postscript, you have to first convert it to PDF using Acrobat 47 | Distiller or *ps2pdf*.) Once converted to XML, the file can be opened 48 | from Ipe as usual. 49 | 50 | The conversion process should handle any graphics in the PDF file 51 | fine, but doesn't do very well on text - Ipe's text model is just too 52 | different. 53 | 54 | 55 | ipe5toxml 56 | --------- 57 | 58 | If you still have figures that were created with Ipe 5, you can use 59 | *ipe5toxml* to convert them to Ipe 6 format. You can then use 60 | *ipe6upgrade* to convert them to Ipe 7 format. 61 | 62 | 63 | figtoipe 64 | -------- 65 | 66 | Figtoipe converts a figure in FIG format into an Ipe XML-file. This 67 | is useful if you used to make figures with Xfig before discovering 68 | Ipe, of if your co-authors made figures for your article with Xfig 69 | (converting them will have the added benefit of forcing your 70 | co-authors to learn to use Ipe). Finally, there are quite a number of 71 | programs that can export to FIG format, and *figtoipe* effectively 72 | turns that into the possibility of exporting to Ipe. 73 | 74 | However, *figtoipe* is not quite complete. The drawing models of FIG 75 | and Ipe are also somewhat different, which makes it impossible to 76 | properly render some FIG files in Ipe. Ipe does not support depth 77 | ordering independent of grouping, pattern fill, and Postscript fonts. 78 | You may therefore have to edit the file after conversion. 79 | 80 | *figtoipe* is now maintained by Alexander Bürger. 81 | 82 | -------------------------------------------------------------------------------- /figtoipe/figtoipe.1: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .\" First parameter, NAME, should be all caps 3 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 4 | .\" other parameters are allowed: see man(7), man(1) 5 | .\" TeX users may be more comfortable with the \fB\fP and 6 | .\" \fI\fP escape sequences to invode bold face and italics, 7 | .\" respectively. 8 | .TH FIGTOIPE 1 "April 26, 2008" 9 | .\" Please adjust this date whenever revising the manpage. 10 | .\" 11 | .\" Some roff macros, for reference: 12 | .\" .nh disable hyphenation 13 | .\" .hy enable hyphenation 14 | .\" .ad l left justify 15 | .\" .ad b justify to both left and right margins 16 | .\" .nf disable filling 17 | .\" .fi enable filling 18 | .\" .br insert line break 19 | .\" .sp insert n+1 empty lines 20 | .\" for manpage-specific macros, see man(7) 21 | .SH NAME 22 | figtoipe \- Convert FIG figures into Ipe format 23 | .SH SYNOPSIS 24 | .B figtoipe 25 | \fP[\-g] [\-p \fIpreamble\fP] 26 | \fIFIGfile\fP \fIXMLfile\fP 27 | 28 | .SH DESCRIPTION 29 | 30 | \fBfigtoipe\fP converts files in FIG format (as created, e.g., by 31 | \fBxfig\fP) to Ipe's XML format. 32 | 33 | \fBfigtoipe\fP is not complete. The main lacking feature is the 34 | conversion of splines. Arc-boxes are replaced by rectangles. Feel 35 | free to improve this version! 36 | 37 | The drawing models of FIG and Ipe are somewhat different. Ipe does 38 | not support depth ordering independent of grouping, pattern fill, and 39 | Postscript fonts. 40 | 41 | \fBfigtoipe\fP tries to include images specified in the XFIG file. For 42 | JPEG pictures, it tries include the compressed image data into the XML 43 | file. For files not recognized as JPEG, \fBanytopnm\fP is called; its 44 | output is compressed and included in the XML file. Some output of 45 | \fBanytopnm\fP might be rejected (e.g. images larger than 5000x5000 46 | pixels or B&W bitmaps), or misunderstood. 47 | 48 | .SH OPTIONS 49 | .B \-g 50 | group the figure in the output XML 51 | .TP 52 | .B \-c 53 | tell ipe to crop PDF output to the boundingbox 54 | .TP 55 | .B \-6 56 | write in ipe 6 format instead of ipe 7 format 57 | .TP 58 | .B \-p \fIlatex\fP 59 | add \fIlatex\fP as a preamble to the generated XML file, e.g. 60 | .nf 61 | .in +.5i 62 | \'\\usepackage{amsmath}\' 63 | .in -.5i 64 | .fi 65 | 66 | .SH AUTHORS 67 | .ft CW 68 | .nf 69 | \&Otfried Cheong 70 | \&Alexander B\[:u]rger (image handling) 71 | .ft R 72 | .fi 73 | 74 | .SH REPORTING BUGS 75 | .ad l 76 | Please report bugs using Ipe bugzilla at 77 | .I "https://github.com/otfried/ipe-tools/issues" 78 | 79 | .SH SEE ALSO 80 | .ad l 81 | More information about Ipe can be found in 82 | .IR "The Ipe Manual" , 83 | which can be found in your Ipe installation. 84 | 85 | .SH LICENSE & WARRANTY 86 | .ad l 87 | \fBfigtoipe\fP comes with ABSOLUTELY NO WARRANTY. It is free software; 88 | you can redistribute it and/or modify it under the terms of the GNU 89 | General Public License as published by the Free Software Foundation; 90 | either version 2 of the License, or (at your option) any later 91 | version. 92 | 93 | See the file \fBgpl.txt\fP accompanying the source for details. 94 | -------------------------------------------------------------------------------- /appimage/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Download and install all prerequisites for making the Ipe AppImage 4 | # 5 | 6 | # Halt on errors 7 | set -e 8 | 9 | ###################################################### 10 | # install packages 11 | ###################################################### 12 | # epel-release for newest Qt and stuff 13 | sudo yum -y install epel-release 14 | sudo yum -y install readline-devel zlib-devel cairo-devel 15 | sudo yum -y install cmake binutils fuse glibc-devel glib2-devel fuse-devel gcc zlib-devel # AppImageKit dependencies 16 | sudo yum -y install poppler-devel 17 | 18 | # Need a newer gcc, getting it from Developer Toolset 2 19 | sudo wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtools-2.repo 20 | sudo yum -y install devtoolset-2-gcc devtoolset-2-gcc-c++ devtoolset-2-binutils 21 | # /opt/rh/devtoolset-2/root/usr/bin/gcc 22 | # now holds gcc and c++ 4.8.2 23 | #scl enable devtoolset-2 24 | source /opt/rh/devtoolset-2/enable 25 | 26 | ###################################################### 27 | # Install Qt 28 | ###################################################### 29 | #wget http://download.qt.io/official_releases/online_installers/qt-unified-linux-x86-online.run 30 | #chmod +x qt-unified-linux-x86-online.run 31 | #./qt-unified-linux-x86-online.run --script qt-installer-noninteractive.qs 32 | # wget http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-linux-x64-5.5.1.run 33 | # chmod +x qt-opensource-linux-x64-5.5.1.run 34 | # ./qt-opensource-linux-x64-5.5.1.run --script qt-installer-noninteractive.qs 35 | 36 | sudo yum -y install qt5-qtbase-devel qt5-qtbase-gui 37 | # qt5-qtlocation-devel qt5-qtscript-devel qt5-qtwebkit-devel qt5-qtsvg-devel qt5-linguist qt5-qtconnectivity-devel 38 | 39 | ###################################################### 40 | # build libraries from source 41 | ###################################################### 42 | # Change directory to build. Everything happens in build. 43 | mkdir build 44 | cd build 45 | 46 | # libjpeg 47 | wget http://www.ijg.org/files/jpegsrc.v8d.tar.gz 48 | tar xfvz jpegsrc.v8d.tar.gz 49 | cd jpeg-8d 50 | ./configure && make && sudo make install 51 | cd .. 52 | 53 | # lua 54 | wget http://www.lua.org/ftp/lua-5.3.3.tar.gz 55 | tar xfvz lua-5.3.3.tar.gz 56 | cd lua-5.3.3/src 57 | #sed -i 's/^CFLAGS=/CFLAGS= -fPIC /g' Makefile 58 | cd .. 59 | make linux CFLAGS="-fPIC" 60 | sudo make install 61 | cd .. 62 | 63 | # libpng 64 | wget http://download.sourceforge.net/libpng/libpng-1.6.21.tar.gz 65 | tar xfvz libpng-1.6.21.tar.gz 66 | cd libpng-1.6.21 67 | ./configure 68 | make check 69 | sudo make install 70 | cd .. 71 | 72 | # qhull 73 | wget http://www.qhull.org/download/qhull-2015-src-7.2.0.tgz 74 | tar xfvz qhull-2015-src-7.2.0.tgz 75 | cd qhull-2015.2 76 | make 77 | sudo install -d /usr/local/include/qhull 78 | sudo install -m 0644 src/libqhull/*.h /usr/local/include/qhull 79 | sudo install -m 0755 lib/libqhullstatic.a /usr/local/lib 80 | cd .. 81 | 82 | ###################################################### 83 | # Build AppImageKit (into top level) 84 | ###################################################### 85 | 86 | cd .. 87 | git clone https://github.com/probonopd/AppImageKit.git 88 | cd AppImageKit/ 89 | git checkout master 90 | cmake . 91 | make clean 92 | make 93 | 94 | ###################################################### 95 | -------------------------------------------------------------------------------- /matplotlib/README.md: -------------------------------------------------------------------------------- 1 | matplotlib backend 2 | ================== 3 | 4 | This is an Ipe backend for the [Matplotlib plotting 5 | library](http://matplotlib.org/) for Python, written by Soyeon Baek 6 | and Otfried Cheong. A major rewrite/refactoring for matplotlib >= 3.6 7 | and Python 3 was done by @satemochi in 2025. 8 | 9 | You can create Ipe files directly from Matplotlib. 10 | 11 | 12 | Quick Usage 13 | ----------- 14 | 15 | To use the backend, copy the file *backend_ipe.py* somewhere on your 16 | Python path. (The current directory will do.) 17 | 18 | You activate the backend like this: 19 | 20 | ```python 21 | import matplotlib 22 | matplotlib.use('module://backend_ipe') 23 | ``` 24 | 25 | The Ipe backend allows you to save in Ipe format: 26 | 27 | ```python 28 | plt.savefig("my_plot.ipe", format="ipe") 29 | ``` 30 | 31 | or, simply 32 | ```python 33 | plt.savefig("my_plot.ipe") 34 | ``` 35 | 36 | 37 | Requirements 38 | ------------ 39 | - Python >=3.6 40 | - Matplotlib >=3.6 41 | 42 | If either `Python` or `Matplotlib` is older than the version 3.6, 43 | please switch to using `backend_ipe.py` from a previous version 44 | in the directory `past`. 45 | 46 | 47 | 48 | Options 49 | ------- 50 | 51 | Some plots need to measure the size of text to place labels correctly 52 | (see the *tests/legend_demo.py* test for an example). The Ipe backend can use 53 | a background Latex process to measure the dimensions of text as it 54 | will appear in the Ipe document. By default this is not enabled, as 55 | most plots don't need it and it slows down the processing of the plot. 56 | 57 | If you want to enable text size measuring, set the matplotlib option 58 | *ipe.textsize* to True, for instance like this: 59 | 60 | ```python 61 | import matplotlib 62 | matplotlib.use('module://backend_ipe') 63 | import matplotlib.pyplot as plt 64 | matplotlib.rcParams['ipe.textsize'] = True 65 | ``` 66 | 67 | (Note that the *ipe* options are only available after the backend has 68 | been loaded, here caused by importing *pyplot*.) 69 | 70 | 71 | If you want your plot to include an Ipe stylesheet, specify this using 72 | the option *ipe.stylesheet*, with a full pathname. (If you don't know 73 | where your style sheets are, use Ipe -> Help -> Show Configuration.) 74 | Here is an example: 75 | 76 | ```python 77 | import matplotlib 78 | matplotlib.use('module://backend_ipe') 79 | import matplotlib.pyplot as plt 80 | matplotlib.rcParams['ipe.stylesheet'] = "/sw/ipe/share/ipe/7.1.6/styles/basic.isy" 81 | ``` 82 | 83 | You can set the preamble of the Ipe document using the option 84 | *ipe.preamble*. This is useful, for instance, when you want to use 85 | font sizes that are not available with the standard fonts (the test 86 | *watermark_image* needs this). You can then switch to a Postscript 87 | font that can be scaled to any size: 88 | 89 | ```python 90 | import matplotlib 91 | matplotlib.use('module://backend_ipe') 92 | import matplotlib.pyplot as plt 93 | matplotlib.rcParams['ipe.preamble'] = r""" 94 | \usepackage{times} 95 | """ 96 | ``` 97 | 98 | 99 | 100 | Problems? 101 | --------- 102 | 103 | If you need to report a problem, please include your matplotlib version. 104 | You can find it as follows: 105 | 106 | ```python 107 | import matplotlib 108 | print(matplotlib.__version__) 109 | ``` 110 | -------------------------------------------------------------------------------- /svgtoipe/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Svgtoipe 3 | ======== 4 | 5 | This is Svgtoipe, a Python script that reads SVG figures and generates 6 | an XML file readable by Ipe. 7 | 8 | You'll need Python3 installed on your system. To process embedded 9 | images in SVG figures will also require the Python Image Library 10 | (PIL). (On Ubuntu/Debian, install python3-image). 11 | 12 | For installation, just copy "svgtoipe" to a suitable location on your 13 | system. 14 | 15 | You can report bugs on the issue tracking system at 16 | "https://github.com/otfried/ipe-tools/issues". 17 | 18 | Before reporting a bug, check that you have the latest version of 19 | Svgtoipe, and check the existing reports to see whether your bug has 20 | already been reported. Please do not send bug reports directly to me 21 | (the first thing I would do with the report is to enter it into the 22 | bug tracking system). 23 | 24 | Suggestions for features, or random comments on Svgtoipe can be sent 25 | to the Ipe discussion mailing list at . If you 26 | have problems installing or using Svgtoipe, the Ipe discussion mailing 27 | list would also be the best place to ask. 28 | 29 | You can send suggestions or comments directly to me by Email, but you 30 | should then not expect a reply. I cannot dedicate much time to Ipe, 31 | and the little time I have I prefer to put into development. I'm much 32 | more likely to get involved in a discussion of desirable features on 33 | the mailing list, where anyone interested can participate than by 34 | direct Email. 35 | 36 | Otfried Cheong 37 | Dept. of Computer Science 38 | KAIST 39 | Daejeon, South Korea 40 | Email: ipe@otfried.org 41 | Ipe webpage: http://ipe.otfried.org 42 | 43 | -------------------------------------------------------------------- 44 | 45 | Copyright (C) 2009-2024 Otfried Cheong 46 | 47 | svgtoipe is free software; you can redistribute it and/or modify it 48 | under the terms of the GNU General Public License as published by the 49 | Free Software Foundation; either version 3 of the License, or (at your 50 | option) any later version. 51 | 52 | svgtoipe is distributed in the hope that it will be useful, but 53 | WITHOUT ANY WARRANTY; without even the implied warranty of 54 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 55 | General Public License for more details. 56 | 57 | You should have received a copy of the GNU General Public License 58 | along with svgtoipe; if not, you can find it at 59 | "http://www.gnu.org/copyleft/gpl.html", or write to the Free Software 60 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 61 | 62 | -------------------------------------------------------------------- 63 | 64 | Changes 65 | ======= 66 | 67 | * 2024/05/16 68 | Fix warnings on regular expressions on Python 3.12 (#64). 69 | 70 | * 2019/12/10 71 | Add rudimentary support for and (thanks to Lukas 72 | Barth #40). 73 | 74 | * 2019/08/01 75 | Handle missing attributes in various elements. More color 76 | keywords. A test script to go through SVG samples. Handle 'a' 77 | elements. Default for 'fill' is black. 78 | 79 | * 2019/06/02 80 | Handle coordinates without a digit before the period. 81 | Migrate to Python 3. 82 | 83 | * 2016/12/09 84 | Command line argument to generate Ipe selection format, ability to 85 | read/write stdin/stdout (thanks to Christian Kapeller). 86 | 87 | * 2013/11/07 88 | Bugs in path parsing and Latex generation fixed by Will Evans. 89 | 90 | * 2010/06/08 91 | Added copyright notice and GPL license to svgtoipe distribution. 92 | 93 | * 2009/10/18 94 | First version of svgtoipe. 95 | 96 | -------------------------------------------------------------------- 97 | -------------------------------------------------------------------------------- /snap/README.md: -------------------------------------------------------------------------------- 1 | # Ipe in a snap 2 | 3 | Linux users suffer from the problem that Linux distributions provide 4 | packages for rather old versions of Ipe. For instance, Ubuntu 16.04 5 | still provides Ipe 7.1.10 (from late 2015). Distributions tend to be 6 | conservative to ensure the stability of the system. 7 | 8 | [**Snappy**](http://snapcraft.io) is a new system that provides apps 9 | in *encapsulated blocks* called **snaps**. A bug in a snap does not 10 | affect the robustness of the remaining sytem, and so users can freely 11 | upgrade individual snaps at will. From now on, Ipe will provide an 12 | up-to-date snap for each Ipe release, such that Linux users, like 13 | Windows and OSX users, can upgrade easily and immediately. 14 | 15 | Snappy is available on recent Linux distributions such as Ubuntu 16 | 16.04, etc. You install the system by installing the **snapd** 17 | package. On Ubuntu or Debian, you would use 18 | 19 | ``` 20 | sudo apt-get install snapd 21 | ``` 22 | 23 | See http://snapcraft.io/docs/core/install for how to install Snapcraft 24 | on other Linux distributions such as Fedora, 25 | 26 | 27 | ## Installing Ipe in a snap 28 | 29 | Once you have the **snap** command on your system, you can install the 30 | most recent version of Ipe by saying 31 | 32 | ``` 33 | sudo snap install ipe --edge 34 | ``` 35 | 36 | You can now start Ipe by simply saying `ipe` (which calls 37 | `/snap/bin/ipe`). Note that the other Ipe commands are available as 38 | `ipe.ipetoipe`, `ipe.iperender`, etc. 39 | 40 | 41 | ## How Ipe uses Pdflatex 42 | 43 | Snappy isolates each snap to ensure the robustness of the system when 44 | a snap misbehaves. This implies some severe restrictions: Ipe does 45 | not have access to your system's files (with the exception of the 46 | files in your home directory that do not start with a dot). In 47 | particular, Ipe does not have access to the Latex installation on your 48 | system! 49 | 50 | To allow Ipe to run *pdflatex*, the Ipe snap contains a *small Texlive 51 | installation*. You will need to remember this when Ipe fails to find 52 | a Latex style or package. In this case, you will need to install the 53 | Latex package **inside** the snap. 54 | 55 | Note that the following commands are exposed by the snap to help you 56 | find Latex problems: `ipe.pdflatex`, `ipe.lualatex`, `ipe.kpsewhich`. 57 | 58 | 59 | ## Installing additional Latex packages 60 | 61 | You cannot actually add additional Latex packages to the Texlive 62 | installation inside a snap, as snaps reside entirely in read-only 63 | memory. However, Ipe's Latex installation can use a *user tree* where 64 | you can add additional styles and fonts. To install into this user 65 | tree, you run the *texlive manager* `tlmgr` contained in the snap. 66 | For technical reasons, it has to be run from outside the snap, like 67 | this: 68 | 69 | ``` 70 | /snap/ipe/current/bin/tlmgr install dante-logo 71 | ``` 72 | 73 | 74 | ## What doesn't work? 75 | 76 | * The Ipe icon is not shown on the desktop (apparently a bug in 77 | snappy). 78 | 79 | * Opening the manual from the Ipe Help menu currently doesn't work 80 | (apparently a bug in snappy). You can read the manual by opening 81 | the file `/snap/ipe/current/ipe/doc/manual.html`. 82 | 83 | * Declaring an external editor doesn't work. This is currently a 84 | fundamental limitation of snappy (Ipe has no access to running an 85 | editor program that lives outside the snap). 86 | 87 | 88 | ## Anything else? 89 | 90 | If you want to customize Ipe, you will need to know that some files 91 | are in locations different from a classic Linux setup. Use *Show 92 | configuration* in the Help menu to find the right place. For 93 | instance, Ipe runs Latex in `~/snap/ipe/current/latexrun` (rather than 94 | `~/.ipe/latexrun`), and the ipelet directory is 95 | `~/snap/ipe/common/ipelets` rather than `~/.ipe/ipelets`. 96 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: ipe 2 | version: 7.2.7 3 | summary: Ipe http://ipe.otfried.org/ 4 | description: Drawing editor for creating figures in PDF format. 5 | Ipe supports making small figures for inclusion into LaTeX 6 | documents as well as making multi-page PDF presentations. 7 | Ipe's main features are 8 | * Entry of text as LaTeX source code. This makes it easy to enter 9 | mathematical expressions, and to reuse the LaTeX-macros of the main 10 | document. In the display text is displayed as it will appear in 11 | the figure. 12 | * Produces pure Postscript/PDF, including the text. Ipe converts the 13 | LaTeX-source to PDF or Postscript when the file is saved. 14 | * It is easy to align objects with respect to each other (for 15 | instance, to place a point on the intersection of two lines, or to 16 | draw a circle through three given points) using various snapping 17 | modes. 18 | * Users can provide ipelets (Ipe plug-ins) to add functionality to 19 | Ipe. This way, Ipe can be extended for each task at hand. 20 | * The text model is based on Unicode, and has been tested with Korean, 21 | Chinese, and Japanese. 22 | 23 | grade: devel 24 | confinement: strict 25 | 26 | parts: 27 | ipe: 28 | source: https://dl.bintray.com/otfried/generic/ipe/7.2/ipe-7.2.7-src.tar.gz 29 | source-subdir: src 30 | plugin: make 31 | make-parameters: 32 | - IPESNAPCRAFT=1 33 | - IPEQVORONOI=1 34 | - QT_SELECT=5 35 | - IPESTRICT=1 36 | build-packages: 37 | - libcairo2-dev 38 | - libfreetype6-dev 39 | - liblua5.3-dev 40 | - libjpeg8-dev 41 | - libpng12-dev 42 | - make 43 | - qtbase5-dev 44 | - qtbase5-dev-tools 45 | - zlib1g-dev 46 | - libqhull-dev 47 | after: [desktop-qt5] 48 | 49 | wrapper: 50 | plugin: dump 51 | source: ./wrapper 52 | organize: 53 | wrapper.sh: bin/wrapper.sh 54 | tlmgr.sh: bin/tlmgr 55 | 56 | texlive: 57 | plugin: texlive 58 | source: http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz 59 | build-packages: 60 | - wget 61 | prime: 62 | - -texlive/texmf-dist/doc 63 | - -texlive/texmf-dist/source 64 | - -texlive/texmf-dist/tex/context 65 | - -texlive/texmf-dist/tex/plain 66 | - -texlive/texmf-var/web2c/luatex/dvi* 67 | - -texlive/texmf-var/web2c/luatex/luatex.* 68 | - -texlive/texmf-var/web2c/luajittex/ 69 | - -texlive/texmf-var/web2c/tex/ 70 | - -texlive/texmf-var/web2c/metafont 71 | - -texlive/texmf-var/web2c/pdftex/etex.* 72 | - -texlive/texmf-var/web2c/pdftex/latex.* 73 | - -texlive/texmf-var/web2c/pdftex/mptopdf.* 74 | - -texlive/texmf-var/web2c/pdftex/pdfetex.* 75 | - -texlive/texmf-var/web2c/pdftex/pdftex.* 76 | - -texlive/bin/x86_64-linux/xdvi* 77 | - -texlive/bin/x86_64-linux/luajittex 78 | - -texlive/bin/x86_64-linux/g* 79 | - -texlive/bin/x86_64-linux/dvi* 80 | 81 | apps: 82 | ipe: 83 | command: desktop-launch wrapper.sh ipe 84 | plugs: [x11, home] 85 | 86 | ipetoipe: 87 | command: wrapper.sh ipetoipe 88 | plugs: [home] 89 | 90 | ipeextract: 91 | command: wrapper.sh ipeextract 92 | plugs: [home] 93 | 94 | iperender: 95 | command: wrapper.sh iperender 96 | plugs: [home] 97 | 98 | ipescript: 99 | command: wrapper.sh ipescript 100 | plugs: [home] 101 | 102 | ipe6upgrade: 103 | command: wrapper.sh ipe6upgrade 104 | plugs: [home] 105 | 106 | pdflatex: 107 | command: wrapper.sh pdflatex 108 | plugs: [home] 109 | 110 | lualatex: 111 | command: wrapper.sh lualatex 112 | plugs: [home] 113 | 114 | bibtex: 115 | command: wrapper.sh bibtex 116 | plugs: [home] 117 | 118 | kpsewhich: 119 | command: wrapper.sh kpsewhich 120 | plugs: [home] 121 | 122 | sh: 123 | command: wrapper.sh sh 124 | plugs: [home] 125 | -------------------------------------------------------------------------------- /matplotlib/past/tests/collections_demo.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import matplotlib.pyplot as plt 4 | from matplotlib import collections, transforms 5 | from matplotlib.colors import colorConverter 6 | import numpy as np 7 | 8 | nverts = 50 9 | npts = 100 10 | 11 | # Make some spirals 12 | r = np.array(range(nverts)) 13 | theta = np.array(range(nverts)) * (2*np.pi)/(nverts-1) 14 | xx = r * np.sin(theta) 15 | yy = r * np.cos(theta) 16 | spiral = list(zip(xx,yy)) 17 | 18 | # Make some offsets 19 | rs = np.random.RandomState([12345678]) 20 | xo = rs.randn(npts) 21 | yo = rs.randn(npts) 22 | xyo = list(zip(xo, yo)) 23 | 24 | # Make a list of colors cycling through the rgbcmyk series. 25 | colors = [colorConverter.to_rgba(c) for c in ('r','g','b','c','y','m','k')] 26 | 27 | fig, axes = plt.subplots(2,2) 28 | ((ax1, ax2), (ax3, ax4)) = axes # unpack the axes 29 | 30 | 31 | col = collections.LineCollection([spiral], offsets=xyo, 32 | transOffset=ax1.transData) 33 | trans = fig.dpi_scale_trans + transforms.Affine2D().scale(1.0/72.0) 34 | col.set_transform(trans) # the points to pixels transform 35 | # Note: the first argument to the collection initializer 36 | # must be a list of sequences of x,y tuples; we have only 37 | # one sequence, but we still have to put it in a list. 38 | ax1.add_collection(col, autolim=True) 39 | # autolim=True enables autoscaling. For collections with 40 | # offsets like this, it is neither efficient nor accurate, 41 | # but it is good enough to generate a plot that you can use 42 | # as a starting point. If you know beforehand the range of 43 | # x and y that you want to show, it is better to set them 44 | # explicitly, leave out the autolim kwarg (or set it to False), 45 | # and omit the 'ax1.autoscale_view()' call below. 46 | 47 | # Make a transform for the line segments such that their size is 48 | # given in points: 49 | col.set_color(colors) 50 | 51 | ax1.autoscale_view() # See comment above, after ax1.add_collection. 52 | ax1.set_title('LineCollection using offsets') 53 | 54 | 55 | # The same data as above, but fill the curves. 56 | col = collections.PolyCollection([spiral], offsets=xyo, 57 | transOffset=ax2.transData) 58 | trans = transforms.Affine2D().scale(fig.dpi/72.0) 59 | col.set_transform(trans) # the points to pixels transform 60 | ax2.add_collection(col, autolim=True) 61 | col.set_color(colors) 62 | 63 | 64 | ax2.autoscale_view() 65 | ax2.set_title('PolyCollection using offsets') 66 | 67 | # 7-sided regular polygons 68 | 69 | col = collections.RegularPolyCollection(7, 70 | sizes = np.fabs(xx)*10.0, offsets=xyo, 71 | transOffset=ax3.transData) 72 | trans = transforms.Affine2D().scale(fig.dpi/72.0) 73 | col.set_transform(trans) # the points to pixels transform 74 | ax3.add_collection(col, autolim=True) 75 | col.set_color(colors) 76 | ax3.autoscale_view() 77 | ax3.set_title('RegularPolyCollection using offsets') 78 | 79 | 80 | # Simulate a series of ocean current profiles, successively 81 | # offset by 0.1 m/s so that they form what is sometimes called 82 | # a "waterfall" plot or a "stagger" plot. 83 | 84 | nverts = 60 85 | ncurves = 20 86 | offs = (0.1, 0.0) 87 | 88 | yy = np.linspace(0, 2*np.pi, nverts) 89 | ym = np.amax(yy) 90 | xx = (0.2 + (ym-yy)/ym)**2 * np.cos(yy-0.4) * 0.5 91 | segs = [] 92 | for i in range(ncurves): 93 | xxx = xx + 0.02*rs.randn(nverts) 94 | curve = list(zip(xxx, yy*100)) 95 | segs.append(curve) 96 | 97 | col = collections.LineCollection(segs, offsets=offs) 98 | ax4.add_collection(col, autolim=True) 99 | col.set_color(colors) 100 | ax4.autoscale_view() 101 | ax4.set_title('Successive data offsets') 102 | ax4.set_xlabel('Zonal velocity component (m/s)') 103 | ax4.set_ylabel('Depth (m)') 104 | # Reverse the y-axis so depth increases downward 105 | ax4.set_ylim(ax4.get_ylim()[::-1]) 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /pdftoipe/pdftoipe.1: -------------------------------------------------------------------------------- 1 | .\" EMACS: -*- nroff -*- 2 | .\" First parameter, NAME, should be all caps 3 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 4 | .\" other parameters are allowed: see man(7), man(1) 5 | .\" TeX users may be more comfortable with the \fB\fP and 6 | .\" \fI\fP escape sequences to invode bold face and italics, 7 | .\" respectively. 8 | .TH PDFTOIPE 1 "January 3, 2017" 9 | .\" Please adjust this date whenever revising the manpage. 10 | .\" 11 | .\" Some roff macros, for reference: 12 | .\" .nh disable hyphenation 13 | .\" .hy enable hyphenation 14 | .\" .ad l left justify 15 | .\" .ad b justify to both left and right margins 16 | .\" .nf disable filling 17 | .\" .fi enable filling 18 | .\" .br insert line break 19 | .\" .sp insert n+1 empty lines 20 | .\" for manpage-specific macros, see man(7) 21 | .SH NAME 22 | pdftoipe \- Convert PDF files into editable Ipe format 23 | .SH SYNOPSIS 24 | .B pdftoipe 25 | { \fIoptions\fP } \fIPDF file\fP [ \fIXML file\fP ] 26 | 27 | .SH DESCRIPTION 28 | 29 | \fBpdftoipe\fP converts arbitrary PDF files to Ipe's XML format. 30 | 31 | Note that \fBpdftoipe\fP is not related to Ipe's use of the PDF file 32 | format. PDF files generated by Ipe contain an extra stream with Ipe 33 | markup information, which is necessary for Ipe to read the file again. 34 | If you wish to convert an Ipe-generated PDF-file to XML format, you 35 | should use \fIipetoipe -xml\fP! \fBpdftoipe\fP is meant to allow you 36 | to take arbitrary PDF files and make them editable in Ipe. 37 | 38 | \fBpdftoipe\fP does a pretty good job on drawings, but doesn't handle 39 | text very well. Ipe's text model is based on LaTeX, which is just 40 | too different from the text found in most PDF files. 41 | 42 | .TP 43 | \fB-notext\fR 44 | Ignore all text in the PDF file, convert graphics only 45 | .TP 46 | \fB-literal\fR 47 | Allow Latex markup in text objects. The default is to escape all 48 | characters special in Latex. 49 | .TP 50 | \fB-math\fR 51 | Use LaTeX math mode for all text in the PDF file 52 | .TP 53 | \fB-merge\fR \fIint\fP 54 | Set the text merge level, an integer between 0 (the default) and 2. 55 | It determines how eagerly \fBpdftoipe\fP tries to combine consecutive 56 | text in the PDF document into a single Ipe text object. At level 0, 57 | only characters consecutively rendered in PDF are combined. At level 58 | 1, more text is combined. At level 2, all text is combined until a 59 | path or image is drawn. 60 | .TP 61 | \fB-unicode\fR \fIint\fP 62 | Determine what should be done with non-ASCII 63 | characters in text. At level 0, all non-ASCII 64 | characters are represented as \fB[U+XXX]\fR. At level 1 (the 65 | default), some often used characters (such as bullets) are replaced by 66 | Latex equivalents, others are represented as \fB[U+XXX]\fR. 67 | At level 2, characters that are not replaced by Latex equivalents 68 | are included in UTF-8. At level 3, all characters are included as 69 | UTF-8. 70 | 71 | At level 2 and 3, UTF-8 is set as the input encoding in the Latex 72 | preamble of the generated Ipe document. 73 | 74 | Note that this only concerns characters for which the PDF file 75 | provides a mapping to Unicode. Characters from embedded fonts without 76 | Unicode mapping (such as symbol fonts) are always represented as 77 | \fB[S+XX]\fR. 78 | .TP 79 | \fB-f\fR \fIint\fP 80 | First page to convert 81 | .TP 82 | \fB-l\fR \fIint\fP 83 | Last page to convert 84 | .TP 85 | \fB-opw\fR \fIstring\fP 86 | Owner password for encrypted PDF files 87 | .TP 88 | \fB-upw\fP \fIstring\fP 89 | User password for encrypted PDF files 90 | .TP 91 | \fB-q\fP 92 | Quiet mode (don't print any messages or errors) 93 | 94 | .SH AUTHOR 95 | Otfried Cheong 96 | 97 | .SH REPORTING BUGS 98 | .ad l 99 | Please report bugs at 100 | .I "https://github.com/otfried/ipe-tools/issues" 101 | 102 | .SH SEE ALSO 103 | .ad l 104 | More information about Ipe can be found in 105 | .IR "The Ipe Manual" , 106 | available online at 107 | .I "http://ipe.otfried.org/manual/manual.html" 108 | -------------------------------------------------------------------------------- /obs/debian/changelog: -------------------------------------------------------------------------------- 1 | ipe (7.2.29-1) unstable; urgency=medium 2 | 3 | * New version. 4 | 5 | -- Otfried Cheong Sat, 25 May 2024 13:29:00 +0200 6 | 7 | ipe (7.2.28-1) unstable; urgency=medium 8 | 9 | * New version. 10 | 11 | -- Otfried Cheong Sun, 13 Aug 2023 10:24:00 +0200 12 | 13 | ipe (7.2.27-1) unstable; urgency=medium 14 | 15 | * New version. 16 | 17 | -- Otfried Cheong Mon, 08 May 2023 12:44:00 +0200 18 | 19 | ipe (7.2.26-1) unstable; urgency=medium 20 | 21 | * New version. 22 | 23 | -- Otfried Cheong Sat, 16 Jul 2022 16:00:00 +0200 24 | 25 | ipe (7.2.25-1) unstable; urgency=medium 26 | 27 | * New version. 28 | 29 | -- Otfried Cheong Sun, 19 Jun 2022 19:00:00 +0200 30 | 31 | ipe (7.2.24-1) unstable; urgency=medium 32 | 33 | * New version. 34 | 35 | -- Otfried Cheong Wed, 07 Apr 2021 11:50:00 +0200 36 | 37 | ipe (7.2.23-3) unstable; urgency=medium 38 | 39 | * Build a single deb file, including shared libraries. 40 | 41 | -- Otfried Cheong Sat, 26 Dec 2020 19:40:00 +0100 42 | 43 | ipe (7.2.23-2) unstable; urgency=medium 44 | 45 | * Run doxygen as part of the build process. 46 | 47 | -- Otfried Cheong Wed, 23 Dec 2020 12:30:00 +0100 48 | 49 | ipe (7.2.23-1) unstable; urgency=medium 50 | 51 | * New version. 52 | 53 | -- Otfried Cheong Mon, 21 Dec 2020 11:40:00 +0100 54 | 55 | ipe (7.2.22-1) unstable; urgency=medium 56 | 57 | * New version. 58 | 59 | -- Otfried Cheong Sun, 20 Dec 2020 19:17:00 +0100 60 | 61 | ipe (7.2.21-1) unstable; urgency=medium 62 | 63 | * New version. 64 | 65 | -- Otfried Cheong Mon, 26 Oct 2020 17:00:00 +0100 66 | 67 | ipe (7.2.20-1) unstable; urgency=medium 68 | 69 | * New version. 70 | 71 | -- Otfried Cheong Thu, 25 Jun 2020 14:00:00 +0200 72 | 73 | ipe (7.2.19-1) unstable; urgency=medium 74 | 75 | * New version. 76 | 77 | -- Otfried Cheong Sun, 14 Jun 2020 15:00:00 +0200 78 | 79 | ipe (7.2.18-1) unstable; urgency=medium 80 | 81 | * New version. 82 | 83 | -- Otfried Cheong Wed, 20 May 2020 22:40:00 +0200 84 | 85 | ipe (7.2.17-1) unstable; urgency=medium 86 | 87 | * New version. 88 | 89 | -- Otfried Cheong Sat, 09 May 2020 14:44:00 +0200 90 | 91 | ipe (7.2.16-1) unstable; urgency=medium 92 | 93 | * New version. 94 | 95 | -- Otfried Cheong Fri, 01 May 2020 10:00:00 +0200 96 | 97 | ipe (7.2.15-1) unstable; urgency=medium 98 | 99 | * New version. 100 | 101 | -- Otfried Cheong Sun, 26 Apr 2020 10:02:00 +0200 102 | 103 | ipe (7.2.14-1) unstable; urgency=medium 104 | 105 | * New version. 106 | 107 | -- Otfried Cheong Sat, 18 Apr 2020 23:02:00 +0200 108 | 109 | ipe (7.2.13-1) unstable; urgency=medium 110 | 111 | * New version. 112 | 113 | -- Otfried Cheong Mon, 07 Oct 2019 11:56:00 +0200 114 | 115 | ipe (7.2.12-1) unstable; urgency=medium 116 | 117 | * New version. 118 | 119 | -- Otfried Cheong Mon, 06 May 2019 10:40:00 +0100 120 | 121 | ipe (7.2.11-2) unstable; urgency=medium 122 | 123 | * Do not insist on having tex package (it might be installed differently). 124 | 125 | -- Otfried Cheong Sun, 17 Mar 2019 20:30:00 +0100 126 | 127 | ipe (7.2.11-1) unstable; urgency=medium 128 | 129 | * New version. 130 | 131 | -- Otfried Cheong Sat, 09 Mar 2019 13:40:00 +0100 132 | 133 | ipe (7.2.10-1) unstable; urgency=medium 134 | 135 | * New version. 136 | 137 | -- Otfried Cheong Mon, 04 Feb 2019 14:03:00 +0100 138 | 139 | ipe (7.2.9-1) unstable; urgency=medium 140 | 141 | * New version. 142 | 143 | -- Otfried Cheong Wed, 16 Jan 2019 14:20:00 +0100 144 | 145 | ipe (7.2.8-1) unstable; urgency=medium 146 | 147 | * First build on opensuse build service 148 | 149 | -- Otfried Cheong Thu, 10 Jan 2019 16:25:00 +0100 150 | -------------------------------------------------------------------------------- /matplotlib/tests/collections_demo.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from matplotlib import collections, transforms 3 | from matplotlib.colors import colorConverter 4 | import numpy as np 5 | from matplotlib import use 6 | use('module://backend_ipe') 7 | 8 | nverts = 50 9 | npts = 100 10 | 11 | # Make some spirals 12 | r = np.array(range(nverts)) 13 | theta = np.array(range(nverts)) * (2*np.pi)/(nverts-1) 14 | xx = r * np.sin(theta) 15 | yy = r * np.cos(theta) 16 | spiral = list(zip(xx, yy)) 17 | 18 | # Make some offsets 19 | rs = np.random.RandomState([12345678]) 20 | xo = rs.randn(npts) 21 | yo = rs.randn(npts) 22 | xyo = list(zip(xo, yo)) 23 | 24 | # Make a list of colors cycling through the rgbcmyk series. 25 | colors = [colorConverter.to_rgba(c) 26 | for c in ('r', 'g', 'b', 'c', 'y', 'm', 'k')] 27 | 28 | fig, axes = plt.subplots(2, 2) 29 | ((ax1, ax2), (ax3, ax4)) = axes # unpack the axes 30 | 31 | 32 | col = collections.LineCollection([spiral], offsets=xyo, 33 | transOffset=ax1.transData) 34 | trans = fig.dpi_scale_trans + transforms.Affine2D().scale(1.0/72.0) 35 | col.set_transform(trans) # the points to pixels transform 36 | # Note: the first argument to the collection initializer 37 | # must be a list of sequences of x,y tuples; we have only 38 | # one sequence, but we still have to put it in a list. 39 | ax1.add_collection(col, autolim=True) 40 | # autolim=True enables autoscaling. For collections with 41 | # offsets like this, it is neither efficient nor accurate, 42 | # but it is good enough to generate a plot that you can use 43 | # as a starting point. If you know beforehand the range of 44 | # x and y that you want to show, it is better to set them 45 | # explicitly, leave out the autolim kwarg (or set it to False), 46 | # and omit the 'ax1.autoscale_view()' call below. 47 | 48 | # Make a transform for the line segments such that their size is 49 | # given in points: 50 | col.set_color(colors) 51 | 52 | ax1.autoscale_view() # See comment above, after ax1.add_collection. 53 | ax1.set_title('LineCollection using offsets') 54 | 55 | 56 | # The same data as above, but fill the curves. 57 | col = collections.PolyCollection([spiral], offsets=xyo, 58 | transOffset=ax2.transData) 59 | trans = transforms.Affine2D().scale(fig.dpi/72.0) 60 | col.set_transform(trans) # the points to pixels transform 61 | ax2.add_collection(col, autolim=True) 62 | col.set_color(colors) 63 | 64 | 65 | ax2.autoscale_view() 66 | ax2.set_title('PolyCollection using offsets') 67 | 68 | # 7-sided regular polygons 69 | 70 | col = collections.RegularPolyCollection(7, sizes=np.fabs(xx) * 10.0, 71 | offsets=xyo, transOffset=ax3.transData) 72 | trans = transforms.Affine2D().scale(fig.dpi/72.0) 73 | col.set_transform(trans) # the points to pixels transform 74 | ax3.add_collection(col, autolim=True) 75 | col.set_color(colors) 76 | ax3.autoscale_view() 77 | ax3.set_title('RegularPolyCollection using offsets') 78 | 79 | 80 | # Simulate a series of ocean current profiles, successively 81 | # offset by 0.1 m/s so that they form what is sometimes called 82 | # a "waterfall" plot or a "stagger" plot. 83 | 84 | nverts = 60 85 | ncurves = 20 86 | offs = (0.1, 0.0) 87 | 88 | yy = np.linspace(0, 2*np.pi, nverts) 89 | ym = np.amax(yy) 90 | xx = (0.2 + (ym-yy)/ym)**2 * np.cos(yy-0.4) * 0.5 91 | segs = [] 92 | for i in range(ncurves): 93 | xxx = xx + 0.02*rs.randn(nverts) 94 | curve = list(zip(xxx, yy*100)) 95 | segs.append(curve) 96 | 97 | col = collections.LineCollection(segs, offsets=offs) 98 | ax4.add_collection(col, autolim=True) 99 | col.set_color(colors) 100 | ax4.autoscale_view() 101 | ax4.set_title('Successive data offsets') 102 | ax4.set_xlabel('Zonal velocity component (m/s)') 103 | ax4.set_ylabel('Depth (m)') 104 | # Reverse the y-axis so depth increases downward 105 | ax4.set_ylim(ax4.get_ylim()[::-1]) 106 | 107 | plt.savefig('collections_demo.ipe', format='ipe') 108 | -------------------------------------------------------------------------------- /pdftoipe/xmloutputdev.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // -------------------------------------------------------------------- 3 | // XmlOutputDev.h 4 | // -------------------------------------------------------------------- 5 | 6 | #ifndef XMLOUTPUTDEV_H 7 | #define XMLOUTPUTDEV_H 8 | 9 | #include 10 | #include "Object.h" 11 | #include "OutputDev.h" 12 | #include "GfxState.h" 13 | #include "cpp/poppler-version.h" 14 | 15 | class GfxPath; 16 | class GfxFont; 17 | 18 | #define PDFTOIPE_VERSION "2024/11/15" 19 | 20 | #define POPPLER_VERSION_AT_LEAST(major, minor, micro) \ 21 | ((POPPLER_VERSION_MAJOR > (major)) || \ 22 | (POPPLER_VERSION_MAJOR == (major) && POPPLER_VERSION_MINOR > (minor)) || \ 23 | (POPPLER_VERSION_MAJOR == (major) && POPPLER_VERSION_MINOR == (minor) && POPPLER_VERSION_MICRO >= (micro))) 24 | 25 | class XmlOutputDev : public OutputDev 26 | { 27 | public: 28 | 29 | // Open an XML output file, and write the prolog. 30 | XmlOutputDev(const std::string& fileName, XRef *xrefA, Catalog *catalog, 31 | int firstPage, int lastPage); 32 | 33 | // Destructor -- writes the trailer and closes the file. 34 | virtual ~XmlOutputDev(); 35 | 36 | // Check if file was successfully created. 37 | bool isOk() { return ok; } 38 | 39 | bool hasUnicode() const { return iUnicode; } 40 | 41 | void setTextHandling(bool math, bool notext, bool literal, 42 | int mergeLevel, bool noTextSize, int unicodeLevel); 43 | 44 | //---- get info about output device 45 | 46 | // Does this device use upside-down coordinates? 47 | // (Upside-down means (0,0) is the top left corner of the page.) 48 | virtual bool upsideDown() override { return false; } 49 | 50 | // Does this device use drawChar() or drawString()? 51 | virtual bool useDrawChar() override { return true; } 52 | 53 | // Does this device use beginType3Char/endType3Char? Otherwise, 54 | // text in Type 3 fonts will be drawn with drawChar/drawString. 55 | virtual bool interpretType3Chars() override { return false; } 56 | 57 | //----- initialization and control 58 | 59 | // Start a page. 60 | virtual void startPage(int pageNum, GfxState *state, XRef *xrefA) override; 61 | 62 | // End a page. 63 | virtual void endPage() override; 64 | 65 | //----- update graphics state 66 | virtual void updateTextPos(GfxState *state) override; 67 | virtual void updateTextShift(GfxState *state, double shift) override; 68 | 69 | //----- path painting 70 | virtual void stroke(GfxState *state) override; 71 | virtual void fill(GfxState *state) override; 72 | virtual void eoFill(GfxState *state) override; 73 | 74 | //----- text drawing 75 | virtual void drawChar(GfxState *state, double x, double y, 76 | double dx, double dy, 77 | double originX, double originY, 78 | CharCode code, int nBytes, const Unicode *u, int uLen) override; 79 | 80 | //----- image drawing 81 | virtual void drawImage(GfxState *state, Object *ref, Stream *str, 82 | int width, int height, GfxImageColorMap *colorMap, 83 | bool interpolate, const int *maskColors, bool inlineImg) override; 84 | 85 | protected: 86 | void startDrawingPath(); 87 | void startText(GfxState *state, double x, double y); 88 | void finishText(); 89 | void writePSUnicode(int ch); 90 | 91 | void doPath(GfxState *state); 92 | void writePSChar(int code); 93 | void writePS(const char *s); 94 | void writePSFmt(const char *fmt, ...); 95 | void writeColor(const char *prefix, const GfxRGB &rgb, const char *suffix); 96 | 97 | protected: 98 | FILE *outputStream; 99 | int seqPage; // current sequential page number 100 | XRef *xref; // the xref table for this PDF file 101 | bool ok; // set up ok? 102 | bool iUnicode; // has a Unicode character been used? 103 | 104 | bool iIsLiteral; // take latex in text literally 105 | bool iIsMath; // make text objects math formulas 106 | bool iNoText; // discard text objects 107 | bool inText; // inside a text object 108 | bool iNoTextSize; // all text objects at normal size 109 | int iMergeLevel; // text merge level 110 | int iUnicodeLevel; // unicode handling 111 | }; 112 | 113 | // -------------------------------------------------------------------- 114 | #endif 115 | -------------------------------------------------------------------------------- /pdftoipe/parseargs.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * parseargs.h 3 | * 4 | * Command line argument parser. 5 | * 6 | * Copyright 1996-2003 Glyph & Cog, LLC 7 | */ 8 | 9 | //======================================================================== 10 | // 11 | // Modified under the Poppler project - http://poppler.freedesktop.org 12 | // 13 | // Poppler project changes to this file are under the GPLv2 or later license 14 | // 15 | // All changes made under the Poppler project to this file are licensed 16 | // under GPL version 2 or later 17 | // 18 | // Copyright (C) 2008, 2009 Albert Astals Cid 19 | // 20 | // To see a description of the changes please see the Changelog file that 21 | // came with your tarball or type make ChangeLog if you are building from git 22 | // 23 | //======================================================================== 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "parseargs.h" 31 | 32 | /* #include "goo/gstrtod.h" */ 33 | 34 | static const ArgDesc *findArg(const ArgDesc *args, char *arg); 35 | static bool grabArg(const ArgDesc *arg, int i, int *argc, char *argv[]); 36 | 37 | bool parseArgs(const ArgDesc *args, int *argc, char *argv[]) { 38 | const ArgDesc *arg; 39 | int i, j; 40 | bool ok; 41 | 42 | ok = true; 43 | i = 1; 44 | while (i < *argc) { 45 | if (!strcmp(argv[i], "--")) { 46 | --*argc; 47 | for (j = i; j < *argc; ++j) 48 | argv[j] = argv[j+1]; 49 | break; 50 | } else if ((arg = findArg(args, argv[i]))) { 51 | if (!grabArg(arg, i, argc, argv)) 52 | ok = false; 53 | } else { 54 | ++i; 55 | } 56 | } 57 | return ok; 58 | } 59 | 60 | void printUsage(char *program, char *otherArgs, const ArgDesc *args) { 61 | const ArgDesc *arg; 62 | char *typ; 63 | int w, w1; 64 | 65 | w = 0; 66 | for (arg = args; arg->arg; ++arg) { 67 | if ((w1 = strlen(arg->arg)) > w) 68 | w = w1; 69 | } 70 | 71 | fprintf(stderr, "Usage: %s [options]", program); 72 | if (otherArgs) 73 | fprintf(stderr, " %s", otherArgs); 74 | fprintf(stderr, "\n"); 75 | 76 | for (arg = args; arg->arg; ++arg) { 77 | fprintf(stderr, " %s", arg->arg); 78 | w1 = 9 + w - strlen(arg->arg); 79 | switch (arg->kind) { 80 | case argInt: 81 | case argIntDummy: 82 | typ = " "; 83 | break; 84 | case argFP: 85 | case argFPDummy: 86 | typ = " "; 87 | break; 88 | case argString: 89 | case argStringDummy: 90 | typ = " "; 91 | break; 92 | case argFlag: 93 | case argFlagDummy: 94 | default: 95 | typ = ""; 96 | break; 97 | } 98 | fprintf(stderr, "%-*s", w1, typ); 99 | if (arg->usage) 100 | fprintf(stderr, ": %s", arg->usage); 101 | fprintf(stderr, "\n"); 102 | } 103 | } 104 | 105 | static const ArgDesc *findArg(const ArgDesc *args, char *arg) { 106 | const ArgDesc *p; 107 | 108 | for (p = args; p->arg; ++p) { 109 | if (p->kind < argFlagDummy && !strcmp(p->arg, arg)) 110 | return p; 111 | } 112 | return NULL; 113 | } 114 | 115 | static bool grabArg(const ArgDesc *arg, int i, int *argc, char *argv[]) { 116 | int n; 117 | int j; 118 | bool ok; 119 | 120 | ok = true; 121 | n = 0; 122 | switch (arg->kind) { 123 | case argFlag: 124 | *(bool *)arg->val = true; 125 | n = 1; 126 | break; 127 | case argInt: 128 | if (i + 1 < *argc && isInt(argv[i+1])) { 129 | *(int *)arg->val = atoi(argv[i+1]); 130 | n = 2; 131 | } else { 132 | ok = false; 133 | n = 1; 134 | } 135 | break; 136 | case argFP: 137 | if (i + 1 < *argc && isFP(argv[i+1])) { 138 | *(double *)arg->val = atof(argv[i+1]); 139 | n = 2; 140 | } else { 141 | ok = false; 142 | n = 1; 143 | } 144 | break; 145 | case argString: 146 | if (i + 1 < *argc) { 147 | strncpy((char *)arg->val, argv[i+1], arg->size - 1); 148 | ((char *)arg->val)[arg->size - 1] = '\0'; 149 | n = 2; 150 | } else { 151 | ok = false; 152 | n = 1; 153 | } 154 | break; 155 | default: 156 | fprintf(stderr, "Internal error in arg table\n"); 157 | n = 1; 158 | break; 159 | } 160 | if (n > 0) { 161 | *argc -= n; 162 | for (j = i; j < *argc; ++j) 163 | argv[j] = argv[j+n]; 164 | } 165 | return ok; 166 | } 167 | 168 | bool isInt(char *s) { 169 | if (*s == '-' || *s == '+') 170 | ++s; 171 | while (isdigit(*s)) 172 | ++s; 173 | if (*s) 174 | return false; 175 | return true; 176 | } 177 | 178 | bool isFP(char *s) { 179 | int n; 180 | 181 | if (*s == '-' || *s == '+') 182 | ++s; 183 | n = 0; 184 | while (isdigit(*s)) { 185 | ++s; 186 | ++n; 187 | } 188 | if (*s == '.') 189 | ++s; 190 | while (isdigit(*s)) { 191 | ++s; 192 | ++n; 193 | } 194 | if (n > 0 && (*s == 'e' || *s == 'E')) { 195 | ++s; 196 | if (*s == '-' || *s == '+') 197 | ++s; 198 | n = 0; 199 | if (!isdigit(*s)) 200 | return false; 201 | do { 202 | ++s; 203 | } while (isdigit(*s)); 204 | } 205 | if (*s) 206 | return false; 207 | return true; 208 | } 209 | -------------------------------------------------------------------------------- /pdftoipe/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Pdftoipe 3 | ======== 4 | 5 | This is Pdftoipe, a program that tries to read arbitrary PDF files and 6 | to generate an XML file readable by Ipe. 7 | 8 | You can report bugs on the issue tracking system at 9 | "https://github.com/otfried/ipe-tools/issues". 10 | 11 | Before reporting a bug, check that you have the latest version of 12 | Pdftoipe, and check the existing reports to see whether your bug has 13 | already been reported. Please do not send bug reports directly to me 14 | (the first thing I would do with the report is to enter it into the 15 | tracking system). 16 | 17 | Suggestions for features, or random comments on Pdftoipe can be sent 18 | to the Ipe discussion mailing list at 19 | . If you have problems installing or 20 | using Pdftoipe, the Ipe discussion mailing list would also be the best 21 | place to ask. 22 | 23 | You can send suggestions or comments directly to me by Email, but you 24 | should then not expect a reply. I cannot dedicate much time to Ipe, 25 | and the little time I have I prefer to put into development. I'm much 26 | more likely to get involved in a discussion of desirable features on 27 | the mailing list, where anyone interested can participate than by 28 | direct Email. 29 | 30 | Otfried Cheong 31 | Email: ipe@otfried.org 32 | Ipe webpage: http://ipe.otfried.org 33 | 34 | -------------------------------------------------------------------- 35 | 36 | Pdftoipe is free software; you can redistribute it and/or modify it 37 | under the terms of the GNU General Public License as published by the 38 | Free Software Foundation; either version 2 of the License, or (at your 39 | option) any later version. 40 | 41 | -------------------------------------------------------------------- 42 | 43 | Compiling 44 | ========= 45 | 46 | You need the Poppler library (http://poppler.freedesktop.org) v0.86.0 47 | or greater. On Debian/Ubuntu, install the packages 'libpoppler-dev', 48 | 'libpoppler-private-dev', and 'libpoppler-cpp-dev'. 49 | 50 | In source directory, say 51 | 52 | make 53 | 54 | This will create the single executable "pdftoipe". Copy it to 55 | wherever you like. You may also install the man page "pdftoipe.1". 56 | 57 | If there are compilation errors, you most likely have a different 58 | poppler version. Poppler has changed dramatically during the last 59 | releases, as the developers are updating the code to use modern C++. 60 | 61 | If your poppler version is <= v0.68, then you can check out branch 62 | "old-poppler" from the "ipe-tools" repository. If you have a version 63 | between v0.69 and v0.85 and cannot upgrade poppler easily, you need to 64 | look in the release history below and checkout the right release of 65 | the "ipe-tools" repository. 66 | 67 | -------------------------------------------------------------------- 68 | 69 | Changes 70 | ======= 71 | 72 | * 2024/11/15 (v7.2.30.1) 73 | Compatibility with poppler 22.02, 22.03, 22.09 (#67). 74 | 75 | * 2021/09/08 (v7.2.24.1) 76 | Add -notextsize flag. 77 | 78 | * 2020/09/09 (v7.2.20.1) 79 | Compatibility with poppler 0.86.0 (#47). 80 | 81 | * 2019/12/10 (v7.2.13.1) 82 | Compilation with poppler 0.83.0 (#42). 83 | 84 | * 2019/01/08 85 | More changes to compile with poppler 0.73.0. 86 | 87 | * 2018/12/07 88 | Changes to compile with poppler 0.72.0. GString is now based on 89 | std::string and may be getting deprecated soon so get rid of some 90 | uses. 91 | 92 | * 2018/11/01 93 | Poppler keeps changing: gBool -> bool (issue #31). 94 | 95 | * 2018/10/23 96 | Const changes to compile with poppler 0.70 (issue #30). 97 | 98 | * 2018/09/24 99 | Removed Object::memCheck call to compile with poppler 0.69 (bug 100 | #29). 101 | 102 | * 2017/09/19 103 | Fixed formatting of color values from %g to %f. 104 | 105 | * 2017/09/05 106 | Added -std=c++11 flag to Makefile for compiling with new poppler 107 | version. 108 | 109 | * 2014/03/03 110 | Applied patch from bug #138 to fix compilation on newer poppler 111 | versions, as well as fix missing dollar signs for some greek 112 | letters. 113 | 114 | * 2013/01/24 115 | Applied patches from bugs #88 and #112 to fix compilation on 116 | newer poppler versions. 117 | 118 | * 2011/05/17 119 | Built Windows binary and included instructions by Daniel 120 | Beckmann for compiling on Windows in the source download. 121 | 122 | * 2011/01/16 123 | Re-released to clarify that pdftoipe uses GPL V2, compatible with 124 | the poppler license. 125 | 126 | * 2009/10/14 127 | Changed to use libpoppler instead of using Xpdf's code directly. 128 | Generate Ipe 7 format. 129 | 130 | * 2007/05/09 131 | Applied patches provided by Philip Johnson (bug #160) to support 132 | latex markup in text objects, and to handle text transformations. 133 | Improved text transformations, and added -merge option to better 134 | control separation/merging of text. 135 | 136 | * 2005/11/14 137 | Generating header correct for Ipe 6.0 preview 25. 138 | 139 | * 2005/09/17 140 | Fixed handling of transformation matrix for text objects. (Text 141 | was incorrectly positioned if pages had the /Rotate flag on.) 142 | 143 | Added -cyberbit option to automatically insert style sheet for 144 | using the Cyberbit font (but of course it has to be installed 145 | properly to be used from Pdflatex). 146 | 147 | Removed silly dependency on Qt. 148 | 149 | Added conversion of some Unicode characters to Latex macros. 150 | 151 | * 2003/06/30 152 | Added recognition of Unicode text (results in a message to the 153 | user) and escaping of the special Latex characters. 154 | 155 | Fixed generation of incorrect XML files (unterminated 156 | objects). 157 | 158 | * 2003/06/18 159 | Added -notext option to completely ignore all text in PDF file. 160 | 161 | Added man page. 162 | 163 | * 2003/06/13 164 | Packaged pdftoipe separately from Ipe. 165 | 166 | * 2003/06/04 167 | Fixed handling of transformation matrix in Pdftoipe. 168 | 169 | Added option -math to pdftoipe. With this option, all text objects 170 | are turned into math formulas. 171 | 172 | -------------------------------------------------------------------- 173 | -------------------------------------------------------------------------------- /appimage/appimage.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Building an AppImage for Ipe in openSuse Build Service (OBS) 3 | # 4 | # Unfortunately the C++ compiler in the appimage build service is stuck with C++11 5 | # 6 | 7 | app: ipe 8 | # binpatch: true 9 | 10 | build: 11 | # packages which get installed in the build enviroment. Not part of the resulting image. 12 | packages: 13 | - libqt5-qtbase-devel 14 | - liblua5_2 15 | - Lua(devel) 16 | - zlib-devel 17 | - pkgconfig(libpng) 18 | - pkgconfig(libjpeg) 19 | - pkgconfig(freetype2) 20 | - pkgconfig(cairo) 21 | # - pkgconfig(poppler) 22 | 23 | # resources which will become available as part of the source. The "appimage" source service 24 | # needs to be enabled to process these. 25 | git: 26 | - https://github.com/otfried/ipe-tools.git 27 | 28 | # - $BUILD_SOURCE_DIR point to the source directory 29 | # - $BUILD_APPDIR point to the AppDir. This directory will become the content of the AppImage 30 | script: 31 | # Build qhull 32 | - cd $BUILD_SOURCE_DIR 33 | - tar xfvz qhull-2015-src-7.2.0.tgz 34 | - cd qhull-2015.2 35 | - make 36 | - install -d /usr/include/qhull_r 37 | - install -m 0644 src/libqhull_r/*.h /usr/include/qhull_r 38 | - install -m 0755 lib/libqhullstatic_r.a /usr/lib 39 | # Build Ipe 40 | - cd $BUILD_SOURCE_DIR 41 | - tar xzf ipe-7.2.10-src.tar.gz 42 | - cd ipe-7.2.10 43 | - cd src 44 | - export LUA_CFLAGS=`pkg-config --cflags lua` 45 | - export LUA_LIBS=`pkg-config --libs lua` 46 | - export QHULL_CFLAGS="-I/usr/include/qhull_r" 47 | - export QHULL_LIBS="-lqhullstatic_r" 48 | - export IPEPREFIX=$BUILD_APPDIR/usr 49 | - export IPEQVORONOI=1 50 | - export MOC=moc-qt5 51 | - make IPEAPPIMAGE=1 52 | - make install IPEAPPIMAGE=1 53 | - cd $BUILD_SOURCE_DIR/ipe-tools/appimage 54 | - cp ipe.png $BUILD_APPDIR 55 | - cp Ipe.desktop $BUILD_APPDIR 56 | - cp startipe.sh $BUILD_APPDIR/usr/bin 57 | - cp appimage.lua $BUILD_APPDIR/usr/ipe/ipelets 58 | - mkdir -p $BUILD_APPDIR/usr/share/metainfo 59 | - cp Ipe.appdata.xml $BUILD_APPDIR/usr/share/metainfo 60 | # Build pdftoipe 61 | # This currently doesn't work because HEAD on ipe-tools is for poppler >= 0.73 62 | # - cd $BUILD_SOURCE_DIR/ipe-tools/pdftoipe 63 | # - make 64 | # - install -m 0755 pdftoipe $BUILD_APPDIR/usr/bin 65 | # include dependencies 66 | - mkdir -p $BUILD_APPDIR/usr/lib/qt5 67 | - cp -R /usr/lib64/qt5/plugins $BUILD_APPDIR/usr/lib/qt5/ 68 | - set +e 69 | - ldd $BUILD_APPDIR/usr/bin/* | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' $BUILD_APPDIR/usr/lib 70 | - find $BUILD_APPDIR/usr/lib -name "*.so*" | xargs ldd | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' $BUILD_APPDIR/usr/lib 71 | - set -e 72 | # this prevents "symbol lookup error libunity-gtk-module.so: undefined symbol: g_settings_new" on ubuntu 14.04 73 | - rm -f $BUILD_APPDIR/usr/lib/qt5/plugins/platformthemes/libqgtk2.so || true 74 | - rmdir $BUILD_APPDIR/usr/lib/qt5/plugins/platformthemes || true # should be empty after deleting libqgtk2.so 75 | - rm -f $BUILD_APPDIR/usr/lib/libgio* || true # these are not needed if we don't use gtk 76 | # Remove unused parts of Qt 77 | - rm -f $BUILD_APPDIR/usr/lib/libQt5PrintSupport.so.5 || true 78 | - rm -f $BUILD_APPDIR/usr/lib/libQt5Network.so.5 || true 79 | - rm -f $BUILD_APPDIR/usr/lib/libQt5Sql.so.5 || true 80 | # Delete potentially dangerous libraries 81 | - rm -f $BUILD_APPDIR/usr/lib/libstdc* $BUILD_APPDIR/usr/lib/libgobject* $BUILD_APPDIR/usr/lib/libc.so.* || true 82 | # The following are assumed to be part of the base system 83 | - rm -f $BUILD_APPDIR/usr/lib/libgtk-x11-2.0.so.0 || true # this prevents Gtk-WARNINGS about missing themes 84 | - rm -f $BUILD_APPDIR/usr/lib/libdbus-1.so.3 || true # this prevents '/var/lib/dbus/machine-id' error on fedora 22/23 live cd 85 | - rm -f $BUILD_APPDIR/usr/lib/libGL.so.* || true 86 | - rm -f $BUILD_APPDIR/usr/lib/libdrm.so.* || true 87 | - rm -f $BUILD_APPDIR/usr/lib/libxcb.so.1 || true 88 | - rm -f $BUILD_APPDIR/usr/lib/libX11.so.6 || true 89 | - rm -f $BUILD_APPDIR/usr/lib/libcom_err.so.2 || true 90 | - rm -f $BUILD_APPDIR/usr/lib/libcrypt.so.1 || true 91 | - rm -f $BUILD_APPDIR/usr/lib/libdl.so.2 || true 92 | - rm -f $BUILD_APPDIR/usr/lib/libexpat.so.1 || true 93 | - rm -f $BUILD_APPDIR/usr/lib/libfontconfig.so.1 || true 94 | - rm -f $BUILD_APPDIR/usr/lib/libgcc_s.so.1 || true 95 | - rm -f $BUILD_APPDIR/usr/lib/libglib-2.0.so.0 || true 96 | - rm -f $BUILD_APPDIR/usr/lib/libgpg-error.so.0 || true 97 | - rm -f $BUILD_APPDIR/usr/lib/libgssapi_krb5.so.2 || true 98 | - rm -f $BUILD_APPDIR/usr/lib/libgssapi.so.3 || true 99 | - rm -f $BUILD_APPDIR/usr/lib/libhcrypto.so.4 || true 100 | - rm -f $BUILD_APPDIR/usr/lib/libheimbase.so.1 || true 101 | - rm -f $BUILD_APPDIR/usr/lib/libheimntlm.so.0 || true 102 | - rm -f $BUILD_APPDIR/usr/lib/libhx509.so.5 || true 103 | - rm -f $BUILD_APPDIR/usr/lib/libICE.so.6 || true 104 | - rm -f $BUILD_APPDIR/usr/lib/libidn.so.11 || true 105 | - rm -f $BUILD_APPDIR/usr/lib/libk5crypto.so.3 || true 106 | - rm -f $BUILD_APPDIR/usr/lib/libkeyutils.so.1 || true 107 | - rm -f $BUILD_APPDIR/usr/lib/libkrb5.so.26 || true 108 | - rm -f $BUILD_APPDIR/usr/lib/libkrb5.so.3 || true 109 | - rm -f $BUILD_APPDIR/usr/lib/libkrb5support.so.0 || true 110 | # rm -f $BUILD_APPDIR/usr/lib/liblber-2.4.so.2 || true # needed for debian wheezy 111 | # rm -f $BUILD_APPDIR/usr/lib/libldap_r-2.4.so.2 || true # needed for debian wheezy 112 | - rm -f $BUILD_APPDIR/usr/lib/libm.so.6 || true 113 | - rm -f $BUILD_APPDIR/usr/lib/libp11-kit.so.0 || true 114 | - rm -f $BUILD_APPDIR/usr/lib/libpcre.so.3 || true 115 | - rm -f $BUILD_APPDIR/usr/lib/libpthread.so.0 || true 116 | - rm -f $BUILD_APPDIR/usr/lib/libresolv.so.2 || true 117 | - rm -f $BUILD_APPDIR/usr/lib/libroken.so.18 || true 118 | - rm -f $BUILD_APPDIR/usr/lib/librt.so.1 || true 119 | - rm -f $BUILD_APPDIR/usr/lib/libsasl2.so.2 || true 120 | - rm -f $BUILD_APPDIR/usr/lib/libSM.so.6 || true 121 | - rm -f $BUILD_APPDIR/usr/lib/libusb-1.0.so.0 || true 122 | - rm -f $BUILD_APPDIR/usr/lib/libuuid.so.1 || true 123 | - rm -f $BUILD_APPDIR/usr/lib/libwind.so.0 || true 124 | - rm -f $BUILD_APPDIR/usr/lib/libz.so.1 || true 125 | # Show what we have done 126 | - find $BUILD_APPDIR/ 127 | -------------------------------------------------------------------------------- /pdftoipe/pdftoipe.cpp: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------- 2 | // Pdftoipe: convert PDF file to editable Ipe XML file 3 | // -------------------------------------------------------------------- 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "goo/GooString.h" 12 | #include "goo/gmem.h" 13 | #include "Object.h" 14 | #include "Stream.h" 15 | #include "Array.h" 16 | #include "Dict.h" 17 | #include "XRef.h" 18 | #include "Catalog.h" 19 | #include "Page.h" 20 | #include "PDFDoc.h" 21 | #include "Error.h" 22 | #include "GlobalParams.h" 23 | 24 | #include "parseargs.h" 25 | #include "xmloutputdev.h" 26 | 27 | static int firstPage = 1; 28 | static int lastPage = 0; 29 | static int mergeLevel = 0; 30 | static int unicodeLevel = 1; 31 | static char ownerPassword[33] = ""; 32 | static char userPassword[33] = ""; 33 | static bool quiet = false; 34 | static bool printHelp = false; 35 | static bool math = false; 36 | static bool literal = false; 37 | static bool notext = false; 38 | static bool noTextSize = false; 39 | 40 | static ArgDesc argDesc[] = { 41 | {"-f", argInt, &firstPage, 0, 42 | "first page to convert"}, 43 | {"-l", argInt, &lastPage, 0, 44 | "last page to convert"}, 45 | {"-opw", argString, ownerPassword, sizeof(ownerPassword), 46 | "owner password (for encrypted files)"}, 47 | {"-upw", argString, userPassword, sizeof(userPassword), 48 | "user password (for encrypted files)"}, 49 | {"-q", argFlag, &quiet, 0, 50 | "don't print any messages or errors"}, 51 | {"-math", argFlag, &math, 0, 52 | "turn all text objects into math formulas"}, 53 | {"-literal", argFlag, &literal, 0, 54 | "allow math mode in input text objects"}, 55 | {"-notext", argFlag, ¬ext, 0, 56 | "discard all text objects"}, 57 | {"-notextsize", argFlag, &noTextSize, 0, 58 | "ignore size of text objects"}, 59 | {"-merge", argInt, &mergeLevel, 0, 60 | "how eagerly should consecutive text be merged: 0, 1, or 2 (default 0)"}, 61 | {"-unicode", argInt, &unicodeLevel, 0, 62 | "how much Unicode should be used: 1, 2, or 3 (default 1)"}, 63 | {"-h", argFlag, &printHelp, 0, 64 | "print usage information"}, 65 | {"-help", argFlag, &printHelp, 0, 66 | "print usage information"}, 67 | {"--help", argFlag, &printHelp, 0, 68 | "print usage information"}, 69 | {"-?", argFlag, &printHelp, 0, 70 | "print usage information"}, 71 | {NULL, argFlag, 0, 0, 0} 72 | }; 73 | 74 | int main(int argc, char *argv[]) 75 | { 76 | // parse args 77 | bool ok = parseArgs(argDesc, &argc, argv); 78 | if (!ok || argc < 2 || argc > 3 || printHelp) { 79 | fprintf(stderr, "pdftoipe version %s\n", PDFTOIPE_VERSION); 80 | printUsage("pdftoipe", " []", argDesc); 81 | return 1; 82 | } 83 | 84 | GooString *fileName = new GooString(argv[1]); 85 | 86 | globalParams = std::make_unique(); 87 | if (quiet) 88 | globalParams->setErrQuiet(quiet); 89 | 90 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 91 | std::optional ownerPW, userPW; 92 | #else 93 | GooString *ownerPW, *userPW; 94 | #endif 95 | if (ownerPassword[0]) { 96 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 97 | ownerPW = GooString(ownerPassword); 98 | #else 99 | ownerPW = new GooString(ownerPassword); 100 | #endif 101 | } else { 102 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 103 | ownerPW = std::nullopt; 104 | #else 105 | ownerPW = 0; 106 | #endif 107 | } 108 | if (userPassword[0]) { 109 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 110 | userPW = GooString(userPassword); 111 | #else 112 | userPW = new GooString(userPassword); 113 | #endif 114 | } else { 115 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 116 | userPW = std::nullopt; 117 | #else 118 | userPW = 0; 119 | #endif 120 | } 121 | 122 | // open PDF file 123 | #if POPPLER_VERSION_AT_LEAST(22, 3, 0) 124 | PDFDoc *doc = new PDFDoc(std::make_unique(fileName->c_str()), ownerPW, userPW); 125 | #else 126 | PDFDoc *doc = new PDFDoc(fileName, ownerPW, userPW); 127 | delete userPW; 128 | delete ownerPW; 129 | #endif 130 | 131 | if (!doc->isOk()) 132 | return 1; 133 | 134 | // construct XML file name 135 | std::string xmlFileName; 136 | if (argc == 3) { 137 | xmlFileName = argv[2]; 138 | } else { 139 | #if POPPLER_VERSION_AT_LEAST(25, 10, 0) 140 | const size_t fileSize = fileName->size(); 141 | #else 142 | const size_t fileSize = fileName->getLength(); 143 | #endif 144 | const char *p = fileName->c_str() + fileSize - 4; 145 | if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) { 146 | xmlFileName = std::string(fileName->c_str(), 147 | fileSize - 4); 148 | } else { 149 | xmlFileName = fileName->c_str(); 150 | } 151 | xmlFileName += ".ipe"; 152 | } 153 | 154 | // get page range 155 | if (firstPage < 1) 156 | firstPage = 1; 157 | 158 | if (lastPage < 1 || lastPage > doc->getNumPages()) 159 | lastPage = doc->getNumPages(); 160 | 161 | // write XML file 162 | XmlOutputDev *xmlOut = 163 | new XmlOutputDev(xmlFileName, doc->getXRef(), 164 | doc->getCatalog(), firstPage, lastPage); 165 | 166 | // tell output device about text handling 167 | xmlOut->setTextHandling(math, notext, literal, mergeLevel, noTextSize, unicodeLevel); 168 | 169 | int exitCode = 2; 170 | if (xmlOut->isOk()) { 171 | doc->displayPages(xmlOut, firstPage, lastPage, 172 | // double hDPI, double vDPI, int rotate, 173 | // bool useMediaBox, bool crop, bool printing, 174 | 72.0, 72.0, 0, false, false, false); 175 | exitCode = 0; 176 | } 177 | 178 | if (xmlOut->hasUnicode()) { 179 | fprintf(stderr, "The document contains Unicode (non-ASCII) text.\n"); 180 | if (unicodeLevel <= 1) 181 | fprintf(stderr, "Unknown Unicode characters were replaced by [U+XXX].\n"); 182 | else 183 | fprintf(stderr, "UTF-8 was set as document encoding in the preamble.\n"); 184 | } 185 | 186 | // clean up 187 | delete xmlOut; 188 | delete doc; 189 | 190 | return exitCode; 191 | } 192 | 193 | // -------------------------------------------------------------------- 194 | -------------------------------------------------------------------------------- /obs/ipe.spec: -------------------------------------------------------------------------------- 1 | %global majorversion 7.2 2 | 3 | Name: ipe 4 | Version: 7.2.29 5 | Release: 1 6 | Summary: Extensible drawing editor 7 | Group: Productivity/Publishing/Presentation 8 | License: GPL-3.0-or-later 9 | #License: GNU General Public License v3.0 or later 10 | URL: http://ipe.otfried.org/ 11 | Source0: %{name}-%{version}.tar.gz 12 | 13 | BuildRequires: desktop-file-utils 14 | BuildRequires: pkgconfig 15 | 16 | BuildRequires: zlib-devel 17 | BuildRequires: libjpeg-devel 18 | BuildRequires: gsl-devel 19 | BuildRequires: libspiro-devel 20 | 21 | BuildRequires: pkgconfig(Qt6Core) 22 | BuildRequires: pkgconfig(Qt6Gui) 23 | BuildRequires: pkgconfig(Qt6Widgets) 24 | BuildRequires: pkgconfig(cairo) >= 1.10.0 25 | BuildRequires: pkgconfig(cairo-ft) >= 1.10.0 26 | BuildRequires: pkgconfig(cairo-pdf) 27 | BuildRequires: pkgconfig(cairo-ps) 28 | BuildRequires: pkgconfig(cairo-svg) 29 | BuildRequires: pkgconfig(freetype2) 30 | BuildRequires: pkgconfig(libpng) 31 | BuildRequires: pkgconfig(lua) >= 5.3 32 | BuildRequires: pkgconfig(libcurl) 33 | %if 0%{?suse_version} 34 | BuildRequires: qt6-tools 35 | %endif 36 | 37 | Requires: qt6-qtsvg 38 | #Requires: tex(latex) 39 | #Requires: xdg-utils 40 | 41 | %description 42 | A drawing editor for creating figures in PDF format. It supports 43 | making small figures for inclusion into LaTeX-documents as well as 44 | making multi-page PDF presentations. 45 | 46 | %package devel 47 | Summary: Header files for writing Ipelets 48 | Group: Development/Libraries/C and C++ 49 | Requires: %{name} = %{version}-%{release} 50 | %description devel 51 | The header files necessary to link against ipelib. 52 | 53 | %if 0%{?suse_version} 54 | # Suse specific 55 | %else 56 | # Other distro 57 | %endif 58 | 59 | %prep 60 | %setup -n %{name}-%{version} -q 61 | 62 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/update-styles.lua 63 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/update-master.lua 64 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/add-style.lua 65 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/onepage.lua 66 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/page-labels.lua 67 | sed -i 's#/usr/bin/env ipescript#/usr/bin/ipescript#' scripts/scratchpad.lua 68 | 69 | %build 70 | export IPEPREFIX="%{_usr}" 71 | export IPELIBDIR="%{_libdir}" 72 | export IPELETDIR="%{_libdir}/ipe/%{version}/ipelets" 73 | export IPECURL=1 74 | export IPE_NO_IPELIB_VERSION_CHECK=1 75 | # I don't know how to install the QtSpell package in a way that works on Fedora and Suse 76 | export IPE_NO_SPELLCHECK=1 77 | 78 | export MOC=%{_qt6_libexecdir}/moc 79 | export LUA_PACKAGE=lua 80 | 81 | pushd src 82 | make %{_smp_mflags} 83 | popd 84 | 85 | %install 86 | export IPEPREFIX="%{_usr}" 87 | export IPELIBDIR="%{_libdir}" 88 | export IPELETDIR="%{_libdir}/ipe/%{version}/ipelets" 89 | pushd src 90 | make INSTALL_ROOT=$RPM_BUILD_ROOT install 91 | popd 92 | 93 | %post -p /sbin/ldconfig 94 | 95 | %postun -p /sbin/ldconfig 96 | 97 | %files 98 | %license doc/gpl.txt 99 | %doc README.md doc/news.txt 100 | 101 | %{_bindir}/ipe 102 | %{_bindir}/ipepresenter 103 | %{_bindir}/ipe6upgrade 104 | %{_bindir}/ipeextract 105 | %{_bindir}/iperender 106 | %{_bindir}/iperender-par 107 | %{_bindir}/ipescript 108 | %{_bindir}/ipetoipe 109 | %{_bindir}/ipecurl 110 | 111 | %{_libdir}/libipe.so.%{version} 112 | %{_libdir}/libipeui.so.%{version} 113 | %{_libdir}/libipecairo.so.%{version} 114 | %{_libdir}/libipecanvas.so.%{version} 115 | %{_libdir}/libipelua.so.%{version} 116 | 117 | %dir %{_libdir}/ipe 118 | %dir %{_libdir}/ipe/%{version} 119 | 120 | %{_libdir}/ipe/%{version}/ipelets 121 | 122 | %dir %{_datadir}/ipe 123 | %dir %{_datadir}/ipe/%{version} 124 | 125 | %{_datadir}/ipe/%{version}/icons 126 | %{_datadir}/ipe/%{version}/lua 127 | %{_datadir}/ipe/%{version}/styles 128 | %{_datadir}/ipe/%{version}/scripts 129 | 130 | %{_mandir}/man1/ipe.1.gz 131 | %{_mandir}/man1/ipe6upgrade.1.gz 132 | %{_mandir}/man1/ipeextract.1.gz 133 | %{_mandir}/man1/iperender.1.gz 134 | %{_mandir}/man1/ipescript.1.gz 135 | %{_mandir}/man1/ipetoipe.1.gz 136 | 137 | %files devel 138 | %{_includedir}/*.h 139 | %{_libdir}/libipe.so 140 | %{_libdir}/libipeui.so 141 | %{_libdir}/libipecairo.so 142 | %{_libdir}/libipecanvas.so 143 | %{_libdir}/libipelua.so 144 | 145 | %changelog 146 | * Sat May 25 2024 Otfried Cheong - 7.2.29-1 147 | - New upstream version. 148 | 149 | * Sun Aug 13 2023 Otfried Cheong - 7.2.28-1 150 | - New upstream version. 151 | 152 | * Mon May 08 2023 Otfried Cheong - 7.2.27-1 153 | - New upstream version. 154 | 155 | * Sat Jul 16 2022 Otfried Cheong - 7.2.26-1 156 | - New upstream version. 157 | 158 | * Sun Jun 19 2022 Otfried Cheong - 7.2.25-1 159 | - New upstream version. 160 | 161 | * Wed Apr 07 2021 Otfried Cheong - 7.2.24-1 162 | - New upstream version. 163 | 164 | * Wed Dec 23 2020 Otfried Cheong - 7.2.23-2 165 | - Run doxygen as part of build process. 166 | 167 | * Mon Dec 21 2020 Otfried Cheong - 7.2.23-1 168 | - New upstream version. 169 | 170 | * Sun Dec 20 2020 Otfried Cheong - 7.2.22-1 171 | - New upstream version. 172 | 173 | * Mon Oct 26 2020 Otfried Cheong - 7.2.21-1 174 | - New upstream version. 175 | 176 | * Thu Jun 25 2020 Otfried Cheong - 7.2.20-1 177 | - New upstream version. 178 | 179 | * Sun Jun 14 2020 Otfried Cheong - 7.2.19-1 180 | - New upstream version. 181 | 182 | * Wed May 20 2020 Otfried Cheong - 7.2.18-1 183 | - New upstream version. 184 | 185 | * Sat May 09 2020 Otfried Cheong - 7.2.17-1 186 | - New upstream version. 187 | 188 | * Fri May 01 2020 Otfried Cheong - 7.2.16-1 189 | - New upstream version. 190 | 191 | * Sun Apr 26 2020 Otfried Cheong - 7.2.15-1 192 | - New upstream version. 193 | 194 | * Sat Apr 18 2020 Otfried Cheong - 7.2.14-1 195 | - New upstream version. 196 | 197 | * Mon Oct 07 2019 Otfried Cheong - 7.2.13-1 198 | - New upstream version. 199 | 200 | * Mon May 06 2019 Otfried Cheong - 7.2.12-1 201 | - New upstream version. 202 | 203 | * Sun Mar 17 2019 Otfried Cheong - 7.2.11-2 204 | - Do not require tex in case user installed it differently. 205 | 206 | * Sat Mar 09 2019 Otfried Cheong - 7.2.11-1 207 | - New upstream version. 208 | 209 | * Mon Feb 04 2019 Otfried Cheong - 7.2.10-1 210 | - New upstream version. 211 | 212 | * Wed Jan 16 2019 Otfried Cheong - 7.2.9-1 213 | - New upstream version. 214 | 215 | * Tue Jan 15 2019 Otfried Cheong - 7.2.8-1 216 | - First try to build Ipe RPMs on openSuse build service. 217 | -------------------------------------------------------------------------------- /appimage/recipe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Halt on errors 4 | set -e 5 | 6 | #scl enable devtoolset-2 7 | source /opt/rh/devtoolset-2/enable 8 | 9 | BASE=`pwd` 10 | IPE=ipe-7.2.8 11 | 12 | APP_DIR=$BASE/Ipe.AppDir 13 | APP_IMAGE=$BASE/$IPE-x86_64.AppImage 14 | 15 | # Cleanup 16 | rm -fr build 17 | rm -fr $APP_DIR $APP_IMAGE 18 | 19 | ###################################################### 20 | # create AppDir 21 | ###################################################### 22 | mkdir $APP_DIR 23 | mkdir -p $APP_DIR/usr/bin/platforms 24 | mkdir -p $APP_DIR/usr/lib/qt5 25 | 26 | # Change directory to build. Everything happens in build. 27 | mkdir -p build 28 | 29 | ###################################################### 30 | # Build Ipe 31 | ###################################################### 32 | 33 | cd $BASE/build 34 | 35 | if [ "x$1" == "xlocal" ]; then 36 | echo "Using local copy of Ipe sources" 37 | cp $HOME/$IPE-src.tar.gz . 38 | else 39 | echo "Downloading Ipe sources" 40 | wget https://dl.bintray.com/otfried/generic/ipe/7.2/$IPE-src.tar.gz 41 | fi 42 | 43 | tar xfvz $IPE-src.tar.gz 44 | 45 | #mkdir $IPE 46 | #rsync -trvz --delete --exclude=.git --exclude=build/obj --exclude=build/Ipe.app $SOURCE_HOST:Devel/ipe/ $IPE/ 47 | 48 | cd $IPE/src 49 | 50 | export QT_SELECT=5 51 | export MOC=moc-qt5 52 | # use libpng16 53 | export PNG_CFLAGS="-I\/usr\/local\/include\/libpng16" 54 | export PNG_LIBS="-lpng16" 55 | export LUA_CFLAGS="-I/usr/local/include" 56 | export LUA_LIBS="-L/usr/local/lib -llua -lm" 57 | export QHULL_CFLAGS="-I/usr/local/include/qhull" 58 | export QHULL_LIBS="-lqhullstatic" 59 | 60 | export IPEPREFIX=$APP_DIR/usr 61 | export IPEQVORONOI=1 62 | 63 | make IPEAPPIMAGE=1 64 | make install IPEAPPIMAGE=1 65 | 66 | ###################################################### 67 | # Build pdftoipe 68 | ###################################################### 69 | 70 | cd $BASE/build 71 | 72 | cp -r $BASE/../pdftoipe . 73 | cd pdftoipe 74 | make 75 | install -m 0755 pdftoipe $APP_DIR/usr/bin 76 | 77 | ###################################################### 78 | # Build exec wrapper (for calling subprocesses) 79 | ###################################################### 80 | 81 | #cd $BASE/build 82 | #git clone git://anongit.kde.org/scratch/brauch/appimage-exec-wrapper.git 83 | #cd appimage-exec-wrapper 84 | #make 85 | #install -m 0755 exec.so $APP_DIR/usr/lib/ 86 | 87 | ###################################################### 88 | # Populate Ipe.AppDir 89 | ###################################################### 90 | 91 | cd $BASE 92 | 93 | cp AppImageKit/AppRun $APP_DIR 94 | cp ipe.png $APP_DIR 95 | cp Ipe.desktop $APP_DIR 96 | cp startipe.sh $APP_DIR/usr/bin 97 | cp appimage.lua $APP_DIR/usr/ipe/ipelets 98 | 99 | cp -R /usr/lib64/qt5/plugins $APP_DIR/usr/lib/qt5/ 100 | cp $APP_DIR/usr/lib/qt5/plugins/platforms/libqxcb.so $APP_DIR/usr/bin/platforms/ 101 | 102 | set +e 103 | ldd $APP_DIR/usr/lib/qt5/plugins/platforms/libqxcb.so | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' $APP_DIR/usr/lib 104 | ldd $APP_DIR/usr/bin/* | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' $APP_DIR/usr/lib 105 | find $APP_DIR/usr/lib -name "*.so*" | xargs ldd | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' $APP_DIR/usr/lib 106 | 107 | set -e 108 | 109 | cp /usr/local/lib/libjpeg.so.8 $APP_DIR/usr/lib 110 | cp /usr/local/lib/libpng16.so.16 $APP_DIR/usr/lib/ 111 | 112 | cp $(ldconfig -p | grep libEGL.so.1 | cut -d ">" -f 2 | xargs) $APP_DIR/usr/lib/ # Otherwise F23 cannot load the Qt platform plugin "xcb" 113 | 114 | # this prevents "symbol lookup error libunity-gtk-module.so: undefined symbol: g_settings_new" on ubuntu 14.04 115 | rm -f $APP_DIR/usr/lib/qt5/plugins/platformthemes/libqgtk2.so || true 116 | rmdir $APP_DIR/usr/lib/qt5/plugins/platformthemes || true # should be empty after deleting libqgtk2.so 117 | rm -f $APP_DIR/usr/lib/libgio* || true # these are not needed if we don't use gtk 118 | 119 | # Removed unused parts of Qt 120 | rm -f $APP_DIR/usr/lib/libQt5PrintSupport.so.5 || true 121 | rm -f $APP_DIR/usr/lib/libQt5Network.so.5 || true 122 | rm -f $APP_DIR/usr/lib/libQt5Sql.so.5 || true 123 | 124 | # Delete potentially dangerous libraries 125 | rm -f $APP_DIR/usr/lib/libstdc* $APP_DIR/usr/lib/libgobject* $APP_DIR/usr/lib/libc.so.* || true 126 | 127 | # The following are assumed to be part of the base system 128 | rm -f $APP_DIR/usr/lib/libgtk-x11-2.0.so.0 || true # this prevents Gtk-WARNINGS about missing themes 129 | rm -f $APP_DIR/usr/lib/libdbus-1.so.3 || true # this prevents '/var/lib/dbus/machine-id' error on fedora 22/23 live cd 130 | rm -f $APP_DIR/usr/lib/libGL.so.* || true 131 | rm -f $APP_DIR/usr/lib/libdrm.so.* || true 132 | rm -f $APP_DIR/usr/lib/libxcb.so.1 || true 133 | rm -f $APP_DIR/usr/lib/libX11.so.6 || true 134 | rm -f $APP_DIR/usr/lib/libcom_err.so.2 || true 135 | rm -f $APP_DIR/usr/lib/libcrypt.so.1 || true 136 | rm -f $APP_DIR/usr/lib/libdl.so.2 || true 137 | rm -f $APP_DIR/usr/lib/libexpat.so.1 || true 138 | rm -f $APP_DIR/usr/lib/libfontconfig.so.1 || true 139 | rm -f $APP_DIR/usr/lib/libgcc_s.so.1 || true 140 | rm -f $APP_DIR/usr/lib/libglib-2.0.so.0 || true 141 | rm -f $APP_DIR/usr/lib/libgpg-error.so.0 || true 142 | rm -f $APP_DIR/usr/lib/libgssapi_krb5.so.2 || true 143 | rm -f $APP_DIR/usr/lib/libgssapi.so.3 || true 144 | rm -f $APP_DIR/usr/lib/libhcrypto.so.4 || true 145 | rm -f $APP_DIR/usr/lib/libheimbase.so.1 || true 146 | rm -f $APP_DIR/usr/lib/libheimntlm.so.0 || true 147 | rm -f $APP_DIR/usr/lib/libhx509.so.5 || true 148 | rm -f $APP_DIR/usr/lib/libICE.so.6 || true 149 | rm -f $APP_DIR/usr/lib/libidn.so.11 || true 150 | rm -f $APP_DIR/usr/lib/libk5crypto.so.3 || true 151 | rm -f $APP_DIR/usr/lib/libkeyutils.so.1 || true 152 | rm -f $APP_DIR/usr/lib/libkrb5.so.26 || true 153 | rm -f $APP_DIR/usr/lib/libkrb5.so.3 || true 154 | rm -f $APP_DIR/usr/lib/libkrb5support.so.0 || true 155 | # rm -f $APP_DIR/usr/lib/liblber-2.4.so.2 || true # needed for debian wheezy 156 | # rm -f $APP_DIR/usr/lib/libldap_r-2.4.so.2 || true # needed for debian wheezy 157 | rm -f $APP_DIR/usr/lib/libm.so.6 || true 158 | rm -f $APP_DIR/usr/lib/libp11-kit.so.0 || true 159 | rm -f $APP_DIR/usr/lib/libpcre.so.3 || true 160 | rm -f $APP_DIR/usr/lib/libpthread.so.0 || true 161 | rm -f $APP_DIR/usr/lib/libresolv.so.2 || true 162 | rm -f $APP_DIR/usr/lib/libroken.so.18 || true 163 | rm -f $APP_DIR/usr/lib/librt.so.1 || true 164 | rm -f $APP_DIR/usr/lib/libsasl2.so.2 || true 165 | rm -f $APP_DIR/usr/lib/libSM.so.6 || true 166 | rm -f $APP_DIR/usr/lib/libusb-1.0.so.0 || true 167 | rm -f $APP_DIR/usr/lib/libuuid.so.1 || true 168 | rm -f $APP_DIR/usr/lib/libwind.so.0 || true 169 | rm -f $APP_DIR/usr/lib/libz.so.1 || true 170 | 171 | # patch hardcoded '/usr/lib' in binaries away 172 | find $APP_DIR/usr/ -type f -exec sed -i -e 's|/usr/lib|././/lib|g' {} \; 173 | 174 | ###################################################### 175 | # Create AppImage 176 | ###################################################### 177 | # Convert the AppDir into an AppImage 178 | $BASE/AppImageKit/AppImageAssistant.AppDir/package $APP_DIR/ $APP_IMAGE 179 | -------------------------------------------------------------------------------- /matplotlib/backend_ipe.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a matplotlib backend to save in the Ipe file format. 3 | (ipe7.sourceforge.net). 4 | 5 | (c) 2014 Soyeon Baek, Otfried Cheong 6 | 7 | You can find the most current version at: 8 | http://www.github.com/otfried/ipe-tools/matplotlib 9 | 10 | You can use this backend by saving it anywhere on your PYTHONPATH. 11 | Use it as an external backend from matplotlib like this: 12 | 13 | import matplotlib 14 | matplotlib.use('module://backend_ipe') 15 | 16 | """ 17 | from codecs import getwriter 18 | from math import cos, radians, sin 19 | from os.path import exists 20 | from re import compile 21 | 22 | from matplotlib import cbook, rcParams 23 | from matplotlib.backend_bases import ( 24 | FigureCanvasBase, FigureManagerBase, RendererBase) 25 | from matplotlib.backends.backend_pgf import LatexManager, _tex_escape 26 | from matplotlib.backends.backend_svg import XMLWriter 27 | from matplotlib.figure import Figure 28 | from matplotlib.path import Path 29 | from matplotlib.rcsetup import validate_bool, validate_string 30 | 31 | 32 | class XMLWriterIpe(XMLWriter): 33 | def insertSheet(self, fname): 34 | self._XMLWriter__flush() 35 | with open(fname, "r", encoding="utf-8") as f: 36 | data = f.read() 37 | if (i := data.find("= 0: 38 | self._XMLWriter__write(data[i:]) 39 | 40 | 41 | rcParams.validate["ipe.preamble"] = validate_string 42 | rcParams.validate["ipe.stylesheet"] = lambda s: s if s and exists(s) else None 43 | rcParams.validate["ipe.textsize"] = validate_bool 44 | _negative_number = compile(r"^\u2212([0-9]+)(\.[0-9]*)?$") 45 | 46 | 47 | class RendererIpe(RendererBase): 48 | def __init__(self, figure, ipewriter): 49 | width, height = figure.get_size_inches() 50 | self.dpi = figure.dpi 51 | self.width = width * self.dpi 52 | self.height = height * self.dpi 53 | self.writer = XMLWriterIpe(ipewriter) 54 | 55 | super().__init__() 56 | rcParams["pgf.texsystem"] = "pdflatex" # use same latex as Ipe 57 | self.__write_header() 58 | self.writer.start("page") 59 | 60 | def __write_header(self): 61 | self._start_id = self.writer.start( 62 | "ipe", 63 | version="70006", 64 | creator="Matplotlib") 65 | self.__stylesheet() 66 | 67 | def __stylesheet(self): 68 | if "ipe.stylesheet" in rcParams and rcParams["ipe.stylesheet"]: 69 | self.writer.insertSheet(rcParams["ipe.stylesheet"]) 70 | self.writer.start("ipestyle", name="opacity") 71 | self.__preamble() 72 | for i in range(10, 100, 10): 73 | self.writer.element("opacity", name=f"{i}%", value=f"{i / 100.0}") 74 | self.writer.end() 75 | 76 | def __preamble(self): 77 | if "ipe.preamble" in rcParams: 78 | self.writer.start("preamble") 79 | self.writer.data(rcParams["ipe.preamble"]) 80 | self.writer.end(indent=False) 81 | 82 | def finalize(self): 83 | self.writer.close(self._start_id) 84 | self.writer.flush() 85 | 86 | def draw_path(self, gc, path, transform, rgbFace=None): 87 | cap = ("butt", "round", "projecting").index(gc.get_capstyle()) 88 | join = ("miter", "round", "bevel").index(gc.get_joinstyle()) 89 | offs, dl = gc.get_dashes() 90 | attrib = {} 91 | if offs is not None and dl is not None: 92 | attrib["dash"] = (f"[{dl}] {offs}" if type(dl) is float else 93 | f"[{' '.join([str(x) for x in dl])}] {offs}") 94 | opaq = gc.get_rgb()[3] 95 | if rgbFace is not None: # filling 96 | r, g, b, opaq = rgbFace 97 | attrib["fill"] = f"{r} {g} {b}" 98 | self.__gen_opacity(attrib, opaq) 99 | self._print_ipe_clip(gc) 100 | _r, _g, _b, _ = gc.get_rgb() 101 | self.writer.start( 102 | "path", 103 | attrib=attrib, 104 | stroke=f"{_r} {_g} {_b}", 105 | pen=f"{gc.get_linewidth()}", 106 | cap=f"{cap}", 107 | join=f"{join}", 108 | fillrule="wind" 109 | ) 110 | self.writer.data(self._make_ipe_path(gc, path, transform)) 111 | self.writer.end() 112 | self._print_ipe_clip_end() 113 | 114 | def _make_ipe_path(self, gc, path, transform): 115 | elem = "" 116 | for points, code in path.iter_segments(transform): 117 | if code == Path.MOVETO: 118 | x, y = tuple(points) 119 | elem += f"{x} {y} m\n" 120 | elif code == Path.CLOSEPOLY: 121 | elem += "h\n" 122 | elif code == Path.LINETO: 123 | x, y = tuple(points) 124 | elem += f"{x} {y} l\n" 125 | elif code == Path.CURVE3: 126 | cx, cy, px, py = tuple(points) 127 | elem += f"{cx} {cy} {px} {py} q\n" 128 | elif code == Path.CURVE4: 129 | c1x, c1y, c2x, c2y, px, py = tuple(points) 130 | elem += (f"{c1x} {c1y} {c2x} {c2y} {px} {py} c\n") 131 | return elem 132 | 133 | def draw_image(self, gc, x, y, im, transform=None): 134 | h, w = im.shape[:2] 135 | if w == 0 or h == 0: 136 | return 137 | self._print_ipe_clip(gc) 138 | self.writer.start( 139 | "image", 140 | width=f"{w}", 141 | height=f"{h}", 142 | ColorSpace="DeviceRGB", 143 | BitsPerComponent="8", 144 | matrix=f"1 0 0 -1 {x} {y}", 145 | rect=f"0 -{h} {w} 0" 146 | ) 147 | for row in im: 148 | for r, g, b, a in row: 149 | self.writer.data(f"{r:02x}{g:02x}{b:02x}") 150 | self.writer.end() 151 | self._print_ipe_clip_end() 152 | 153 | def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): 154 | if _negative_number.match(s): 155 | s = f"${s.replace('\u2212', '-')}$" 156 | attrib = {} 157 | if mtext: 158 | x, y = mtext.get_transform().transform_point(mtext.get_position()) 159 | attrib["halign"] = mtext.get_ha() 160 | attrib["valign"] = mtext.get_va() 161 | 162 | if angle != 0.0: 163 | ra = radians(angle) 164 | sa, ca = sin(ra), cos(ra) 165 | attrib["matrix"] = f"{ca} {sa} -{sa} {ca} {x} {y}" 166 | x, y = 0, 0 167 | 168 | self.__gen_opacity(attrib, gc.get_rgb()[3]) 169 | _r, _g, _b, _ = gc.get_rgb() 170 | self.writer.start( 171 | "text", 172 | stroke=f"{_r} {_g} {_b}", 173 | type="label", 174 | size=f"{prop.get_size_in_points()}", 175 | pos=f"{x} {y}", 176 | attrib=attrib 177 | ) 178 | self.writer.data(f"{_tex_escape(s)}") 179 | self.writer.end(indent=False) 180 | 181 | def _print_ipe_clip(self, gc): 182 | bbox = gc.get_clip_rectangle() 183 | self.use_clip_box = bbox is not None 184 | if self.use_clip_box: 185 | p1, p2 = bbox.get_points() 186 | x1, y1 = p1 187 | x2, y2 = p2 188 | self.writer.start( 189 | "group", 190 | clip=f"{x1} {y1} m {x2} {y1} l {x2} {y2} l {x1} {y2} l h" 191 | ) 192 | clippath, clippath_trans = gc.get_clip_path() # check for clip path 193 | self.use_clip_group = clippath is not None 194 | if self.use_clip_group: 195 | self.writer.start( 196 | "group", 197 | clip=f"{self._make_ipe_path(gc, clippath, clippath_trans)}") 198 | 199 | def _print_ipe_clip_end(self): 200 | if self.use_clip_group: 201 | self.writer.end() 202 | if self.use_clip_box: 203 | self.writer.end() 204 | 205 | def get_canvas_width_height(self): 206 | return self.width, self.height 207 | 208 | def get_text_width_height_descent(self, s, prop, ismath): 209 | if ("ipe.textsize" in rcParams and rcParams["ipe.textsize"] is True): 210 | w, h, d = (LatexManager._get_cached_or_new() 211 | .get_width_height_descent(s, prop)) 212 | return w * (f := (1/72) * self.dpi), h * f, d * f 213 | return 1, 1, 1 214 | 215 | @staticmethod 216 | def __gen_opacity(attrib, opaq): 217 | if opaq < 0.05: 218 | attrib["opacity"] = "10%" 219 | elif opaq < 0.95: 220 | o = round(opaq+10**(-len(str(opaq))-1), 1) 221 | attrib["opacity"] = f"{int(o * 100)}%" 222 | 223 | 224 | class FigureCanvasIpe(FigureCanvasBase): 225 | filetypes = FigureCanvasBase.filetypes.copy() 226 | filetypes["ipe"] = "Ipe 7 file format" 227 | 228 | def print_ipe(self, filename, *args, **kwargs): 229 | with cbook.open_file_cm(filename, "w", encoding="utf-8") as writer: 230 | if not cbook.file_requires_unicode(writer): 231 | writer = getwriter("utf-8")(writer) 232 | self._print_ipe(filename, writer, **kwargs) 233 | 234 | def _print_ipe(self, filename, ipewriter, **kwargs): 235 | self.figure.set_dpi(72.0) 236 | renderer = RendererIpe(self.figure, ipewriter) 237 | self.figure.draw(renderer) 238 | renderer.finalize() 239 | 240 | def get_default_filetype(self): 241 | return "ipe" 242 | 243 | 244 | class FigureManagerIpe(FigureManagerBase): 245 | def __init__(self, *args): 246 | FigureManagerBase.__init__(self, *args) 247 | 248 | 249 | FigureCanvas = FigureCanvasIpe 250 | FigureManager = FigureManagerIpe 251 | 252 | 253 | def new_figure_manager(num, *args, **kwargs): 254 | FigureClass = kwargs.pop("FigureClass", Figure) 255 | fig = FigureClass(*args, **kwargs) 256 | return FigureManagerIpe(FigureCanvasIpe(fig), num) 257 | -------------------------------------------------------------------------------- /poweripe/poweripe.py: -------------------------------------------------------------------------------- 1 | # 2 | # poweripe.py 3 | # 4 | # Translate an Ipe presentation to Powerpoint 5 | # 6 | 7 | import sys, os, re, datetime, argparse 8 | 9 | import pptx 10 | from pptx.util import Pt 11 | from pptx.enum.shapes import MSO_SHAPE 12 | from pptx.enum.text import PP_ALIGN, MSO_AUTO_SIZE, MSO_ANCHOR 13 | 14 | # TODO: maybe use a better Latex parser 15 | # from pylatexenc.latexwalker import LatexWalker, LatexEnvironmentNode 16 | 17 | from PIL import Image 18 | from lxml import etree 19 | 20 | import ipe 21 | 22 | assert sys.hexversion >= 0x3060000 23 | 24 | # -------------------------------------------------------------------- 25 | 26 | # these values are from 'official' Ipe presentation stylesheet 27 | # TODO: compute based on actual stylesheet 28 | sizeMap = { "huge": 2.8 * 17, 29 | "large": 2.8 * 12, 30 | "normal": 2.8 * 10, 31 | "small" : 2.4 * 10, 32 | } 33 | 34 | # Latex definitions are: 35 | latex_sizes = { 36 | "\tiny", 5, 37 | "\footnotesize", 8, 38 | "\small", 9, 39 | "\normalsize", 10, 40 | "\large", 12, 41 | "\Large", 14, 42 | "\LARGE", 17, 43 | "\huge", 20, 44 | "\Huge", 25, 45 | } 46 | 47 | def addBulletToParagraph(p): 48 | size = p.font.size or Pt(18) 49 | el = p._pPr 50 | el.set("marL", "%d" % size) 51 | el.set("indent", "-%d" % size) 52 | nsmap = el.nsmap 53 | el.insert(0, etree.Element("{" + nsmap['a'] + "}buChar", char="\u2022")) 54 | 55 | # -------------------------------------------------------------------- 56 | 57 | class PowerIpe: 58 | def __init__(self, args): 59 | self.args = args 60 | 61 | def findColors(self): 62 | s = self.sheets.allNames("color") 63 | self.colors = {} 64 | for k in s: 65 | sym = s[k] 66 | abs = self.sheets.find("color", sym) 67 | h = "%02x%02x%02x" % (int(abs.r * 255), int(abs.g * 255), int(abs.b * 255)) 68 | rgb = pptx.dml.color.RGBColor.from_string(h) 69 | self.colors[sym] = rgb 70 | 71 | def convertTime(self, s): 72 | return datetime.datetime(int(s[2:6]), 73 | int(s[6:8]), 74 | int(s[8:10]), 75 | int(s[10:12]), 76 | int(s[12:14]), 77 | int(s[14:])) 78 | 79 | def addSvg(self, slide, pageNo, svgobjs): 80 | doc1 = ipe.Document() 81 | doc1.replaceSheets(self.sheets.clone()) 82 | doc1.setProperties(self.iprops) 83 | p1 = doc1[1] 84 | p = self.doc[pageNo] 85 | for i in svgobjs: 86 | obj = p[i] 87 | p1.insert(None, obj.clone(), None, "alpha") 88 | tmpname = "tmpipe%d.ipe" % pageNo 89 | svgname = "tmpipe%d.svg" % pageNo 90 | pngname = "tmpipe%d.png" % pageNo 91 | doc1.save(tmpname, "xml", None) 92 | os.system("iperender -svg -nocrop %s %s" % (tmpname, svgname)) 93 | os.system("iperender -png -nocrop -transparent %s %s" % (tmpname, pngname)) 94 | pic = slide.shapes.add_svg_picture(svgname, pngname, 0, 0) 95 | 96 | def convertText(self, slide, obj): 97 | s = obj.text().strip() 98 | textStyle = obj.get("textstyle") 99 | textSize = obj.get("textsize") 100 | color = obj.get("stroke") 101 | italic = False 102 | bold = False 103 | if s.startswith(r"\bfseries"): 104 | s = s[9:].lstrip() 105 | bold = True 106 | if s.startswith(r"\itshape"): 107 | s = s[8:].lstrip() 108 | italic = True 109 | parSplitRe = "\n[ \t]*\n|\\\\par\\W*" 110 | if textStyle == "itemize" and s.startswith(r"\item"): 111 | s = s[5:].lstrip() 112 | parSplitRe += "|\\\\item" 113 | textStyle = "item" 114 | pars = re.split(parSplitRe, s) 115 | pars = [ s.replace("\n", " ") for s in pars ] 116 | if len(pars) == 0: 117 | return # huh? 118 | box = ipe.Rect() 119 | obj.addToBBox(box, ipe.Matrix()) 120 | pos = box.topLeft() 121 | size = sizeMap.get(textSize, sizeMap["normal"]) 122 | #helper = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Pt(self.x0 + pos.x), Pt(self.y0 - pos.y), 123 | # Pt(box.width()), Pt(box.height())) 124 | txBox = slide.shapes.add_textbox(Pt(self.x0 + pos.x), Pt(self.y0 - pos.y - 0.2 * size), 125 | Pt(box.width()), Pt(box.height())) 126 | tf = txBox.text_frame 127 | tf.word_wrap = True 128 | tf.auto_size = MSO_AUTO_SIZE.NONE 129 | tf.margin_top = 0 130 | tf.margin_left = 0 131 | tf.margin_right = 0 132 | tf.margin_bottom = 0 133 | tf.vertical_anchor = MSO_ANCHOR.TOP 134 | for i in range(len(pars)): 135 | s = pars[i].strip() 136 | s = re.sub(r"\\\\[ \t\n\r\f\v]*", "\v", s) 137 | if i == 0: 138 | p = tf.paragraphs[0] 139 | else: 140 | p = tf.add_paragraph() 141 | p.text = s 142 | p.font.size = Pt(size) 143 | p.line_spacing = Pt(1.2 * size) 144 | if textStyle == "center": 145 | p.alignment = PP_ALIGN.CENTER 146 | elif textStyle == "item": 147 | addBulletToParagraph(p) 148 | if color in self.colors: 149 | p.font.color.rgb = self.colors[color] 150 | p.font.bold = bold 151 | p.font.italic = italic 152 | if "\\textcolor{" in s: 153 | pos = 0 154 | r = p 155 | pat = re.compile("\v|\\\\textcolor{([a-zA-Z0-9]+)}{([^}]+)}") 156 | while True: 157 | m = pat.search(s, pos) 158 | if m is None: 159 | r.text = s[pos:] 160 | break 161 | r.text = s[pos:m.start()] 162 | if m.lastindex is None: 163 | p.add_line_break() 164 | else: 165 | r = p.add_run() 166 | r.text = m.group(2) 167 | runColor = m.group(1) 168 | if runColor in self.colors: 169 | r.font.color.rgb = self.colors[runColor] 170 | r = p.add_run() 171 | pos = m.end() 172 | 173 | # determine if we want to convert this text object 174 | def wantConvertText(self, obj): 175 | if self.args.no_text: 176 | return False 177 | mp = obj.get("minipage") 178 | if not self.args.labels and not mp: 179 | return False 180 | if self.args.latex: 181 | return True 182 | # allow some simple latex 183 | s = obj.text().strip() 184 | if s.startswith("\\itshape"): 185 | s = s[8:] 186 | if s.startswith("\\bfseries"): 187 | s = s[9:] 188 | s = s.replace(r"\\", "") 189 | s = s.replace(r"\textcolor", "") 190 | s = s.replace(r"\item", "") 191 | s = s.replace(r"\par", "") 192 | return not ("\\" in s or "$" in s) 193 | 194 | def embedImage(self, slide, obj): 195 | info = obj.info() 196 | s = str(obj) # make a unique name 197 | imgname = "tmpipe" + s[s.index("@"):] 198 | ext = ".jpg" if info.format == "jpg" else ".ppm" 199 | obj.savePixels(imgname + ext) 200 | if ext == ".ppm": 201 | im = Image.open(imgname + ext) 202 | ext = ".png" 203 | im.save(imgname + ext) 204 | box = ipe.Rect() 205 | obj.addToBBox(box, ipe.Matrix()) 206 | pos = box.topLeft() 207 | pic = slide.shapes.add_picture(imgname + ext, Pt(self.x0 + pos.x), Pt(self.y0 - pos.y), 208 | Pt(box.width()), Pt(box.height())) 209 | 210 | def convertPage(self, pageNo, viewNo): 211 | sys.stderr.write("Converting page %d\n" % pageNo) 212 | p = self.doc[pageNo] 213 | t = p.titles() 214 | if t.title != "": 215 | slide = self.prs.slides.add_slide(self.title_slide_layout) 216 | title_placeholder = slide.shapes.title 217 | title_placeholder.text = t.title 218 | else: 219 | slide = self.prs.slides.add_slide(self.blank_slide_layout) 220 | # First determine which objects we'll convert to svg 221 | svgobjs = set() 222 | for i in range(1, len(p) + 1): 223 | if not p.visible(viewNo, i): 224 | continue 225 | obj = p[i] 226 | ty = obj.type() 227 | if ty == "text" and self.wantConvertText(obj): 228 | pass 229 | elif ty == "image": 230 | self.embedImage(slide, obj) 231 | else: 232 | svgobjs.add(i) 233 | self.addSvg(slide, pageNo, svgobjs) 234 | # Now add remaining objects 235 | for i in range(1, len(p) + 1): 236 | if i in svgobjs or not p.visible(viewNo, i): 237 | continue 238 | obj = p[i] 239 | ty = obj.type() 240 | if ty == "text": 241 | self.convertText(slide, obj) 242 | 243 | def convert(self): 244 | self.doc = ipe.Document(self.args.ipefile) 245 | self.sheets = self.doc.sheets() 246 | self.iprops = self.doc.properties() 247 | self.findColors() 248 | 249 | self.prs = pptx.Presentation() 250 | self.title_slide_layout = self.prs.slide_layouts[5] 251 | self.blank_slide_layout = self.prs.slide_layouts[6] 252 | 253 | props = self.prs.core_properties 254 | props.author = self.iprops.author 255 | props.last_modified_by = "" # shouldn't be python-pptx author 256 | props.title = self.iprops.title 257 | props.created = self.convertTime(self.iprops.created) 258 | props.modified = self.convertTime(self.iprops.modified) 259 | props.keywords = self.iprops.keywords 260 | props.subject = self.iprops.subject 261 | 262 | layout = self.sheets.find("layout") 263 | self.x0 = layout.origin.x 264 | self.y0 = layout.origin.y + layout.papersize.y 265 | 266 | self.prs.slide_width = Pt(layout.papersize.x) 267 | self.prs.slide_height = Pt(layout.papersize.y) 268 | 269 | # set formatting of page title placeholder 270 | tph = self.title_slide_layout.slide_master.placeholders[0] 271 | # make sure the title width is not excessive 272 | tph.width = min(tph.width, Pt(0.8 * layout.papersize.x)) 273 | 274 | for pageNo in range(1, len(self.doc) + 1): 275 | p = self.doc[pageNo] 276 | viewNo = p.countViews() 277 | self.convertPage(pageNo, viewNo) 278 | 279 | pptname = self.args.output 280 | if pptname is None: 281 | pptname = self.args.ipefile[:-4] + '.pptx' 282 | self.prs.save(pptname) 283 | 284 | # -------------------------------------------------------------------- 285 | 286 | if __name__ == "__main__": 287 | parser = argparse.ArgumentParser(description="Convert an Ipe presentation into pptx format") 288 | parser.add_argument('ipefile', help="File name for Ipe input") 289 | parser.add_argument('--output', help="File name for pptx output") 290 | parser.add_argument('--no-text', help="Do not convert text objects", action='store_true') 291 | parser.add_argument('--latex', help="Try to convert Latex text", action='store_true') 292 | parser.add_argument('--labels', help="Also convert label objects, not just minipages", action='store_true') 293 | 294 | powerIpe = PowerIpe(parser.parse_args()) 295 | powerIpe.convert() 296 | 297 | # -------------------------------------------------------------------- 298 | -------------------------------------------------------------------------------- /poweripe/demo-presentation.ipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0 0 m 9 | -1 0.333 l 10 | -1 -0.333 l 11 | h 12 | 13 | 14 | 15 | 16 | 0 0 m 17 | -1 0.333 l 18 | -1 -0.333 l 19 | h 20 | 21 | 22 | 23 | 24 | 0.6 0 0 0.6 0 0 e 25 | 0.4 0 0 0.4 0 0 e 26 | 27 | 28 | 29 | 30 | 0.6 0 0 0.6 0 0 e 31 | 32 | 33 | 34 | 35 | 36 | 0.5 0 0 0.5 0 0 e 37 | 38 | 39 | 0.6 0 0 0.6 0 0 e 40 | 0.4 0 0 0.4 0 0 e 41 | 42 | 43 | 44 | 45 | 46 | -0.6 -0.6 m 47 | 0.6 -0.6 l 48 | 0.6 0.6 l 49 | -0.6 0.6 l 50 | h 51 | -0.4 -0.4 m 52 | 0.4 -0.4 l 53 | 0.4 0.4 l 54 | -0.4 0.4 l 55 | h 56 | 57 | 58 | 59 | 60 | -0.6 -0.6 m 61 | 0.6 -0.6 l 62 | 0.6 0.6 l 63 | -0.6 0.6 l 64 | h 65 | 66 | 67 | 68 | 69 | 70 | -0.5 -0.5 m 71 | 0.5 -0.5 l 72 | 0.5 0.5 l 73 | -0.5 0.5 l 74 | h 75 | 76 | 77 | -0.6 -0.6 m 78 | 0.6 -0.6 l 79 | 0.6 0.6 l 80 | -0.6 0.6 l 81 | h 82 | -0.4 -0.4 m 83 | 0.4 -0.4 l 84 | 0.4 0.4 l 85 | -0.4 0.4 l 86 | h 87 | 88 | 89 | 90 | 91 | 92 | 93 | -0.43 -0.57 m 94 | 0.57 0.43 l 95 | 0.43 0.57 l 96 | -0.57 -0.43 l 97 | h 98 | 99 | 100 | -0.43 0.57 m 101 | 0.57 -0.43 l 102 | 0.43 -0.57 l 103 | -0.57 0.43 l 104 | h 105 | 106 | 107 | 108 | 109 | 110 | 0 0 m 111 | -1 0.333 l 112 | -1 -0.333 l 113 | h 114 | 115 | 116 | 117 | 118 | 0 0 m 119 | -1 0.333 l 120 | -0.8 0 l 121 | -1 -0.333 l 122 | h 123 | 124 | 125 | 126 | 127 | 0 0 m 128 | -1 0.333 l 129 | -0.8 0 l 130 | -1 -0.333 l 131 | h 132 | 133 | 134 | 135 | 136 | -1 0.333 m 137 | 0 0 l 138 | -1 -0.333 l 139 | 140 | 141 | 142 | 143 | 0 0 m 144 | -1 0.333 l 145 | -1 -0.333 l 146 | h 147 | -1 0 m 148 | -2 0.333 l 149 | -2 -0.333 l 150 | h 151 | 152 | 153 | 154 | 155 | 0 0 m 156 | -1 0.333 l 157 | -1 -0.333 l 158 | h 159 | -1 0 m 160 | -2 0.333 l 161 | -2 -0.333 l 162 | h 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | \renewcommand\rmdefault{cmss} 238 | \makeatletter 239 | \leftmargini 1.5em 240 | \leftmargin \leftmargini 241 | \leftmarginii 1.2em 242 | \leftmarginiii 1em 243 | \def\@listI{\leftmargin\leftmargini 244 | \parsep \z@ 245 | \partopsep 3pt 246 | \topsep \z@ 247 | \itemsep \z@} 248 | \@listI 249 | \def\@listii {\leftmargin\leftmarginii 250 | \labelwidth\leftmarginii 251 | \advance\labelwidth-\labelsep 252 | \topsep \z@ 253 | \parsep \z@ 254 | \itemsep \parsep} 255 | \def\@listiii{\leftmargin\leftmarginiii 256 | \labelwidth\leftmarginiii 257 | \advance\labelwidth-\labelsep 258 | \topsep \z@ 259 | \parsep \z@ 260 | \partopsep \z@ 261 | \itemsep \topsep} 262 | \makeatother 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 0 310.652 m 274 | 0 414.874 l 275 | 736 414.874 l 276 | 736 310.652 l 277 | h 278 | 279 | This is the first text with a bullet point. 280 | 281 | This is the second text which is centered and red. 282 | This is the third text which is Huge and \textcolor{lightgreen}{dark} green. 283 | 284 | 285 | 0 498.244 m 286 | 0 528 l 287 | 736 528 l 288 | 736 498.244 l 289 | h 290 | 291 | 292 | 0 446.874 m 293 | 0 466.244 l 294 | 736 466.244 l 295 | 736 446.874 l 296 | h 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 544 128 m 314 | 513.879 190.547 l 315 | 446.198 205.994 l 316 | 391.922 162.711 l 317 | 391.922 93.2893 l 318 | 446.198 50.0058 l 319 | 513.879 65.4535 l 320 | h 321 | 322 | 323 | 324 | 325 | 326 | This is the \textcolor{red}{first} line. 327 | 328 | \textcolor{blue}{This} is the second paragraph. 329 | \par 330 | This is the third \textcolor{purple}{paragraph.} 331 | \item A 332 | \item B 333 | \item C 334 | 335 | 336 | -------------------------------------------------------------------------------- /pdftoipe/xmloutputdev.cpp: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------- 2 | // Output device writing XML stream 3 | // -------------------------------------------------------------------- 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "Object.h" 12 | #include "Error.h" 13 | #include "Gfx.h" 14 | #include "GfxState.h" 15 | #include "GfxFont.h" 16 | #include "Catalog.h" 17 | #include "Page.h" 18 | #include "Stream.h" 19 | 20 | #include "xmloutputdev.h" 21 | 22 | #include 23 | #include 24 | 25 | //------------------------------------------------------------------------ 26 | // XmlOutputDev 27 | //------------------------------------------------------------------------ 28 | 29 | XmlOutputDev::XmlOutputDev(const std::string& fileName, XRef *xrefA, Catalog *catalog, 30 | int firstPage, int lastPage) 31 | { 32 | FILE *f; 33 | 34 | if (!(f = fopen(fileName.c_str(), "wb"))) { 35 | fprintf(stderr, "Couldn't open output file '%s'\n", fileName.c_str()); 36 | ok = false; 37 | return; 38 | } 39 | outputStream = f; 40 | 41 | // initialize 42 | ok = true; 43 | xref = xrefA; 44 | inText = false; 45 | iUnicode = false; 46 | 47 | // set defaults 48 | iIsMath = false; 49 | iNoText = false; 50 | iIsLiteral = false; 51 | iMergeLevel = 0; 52 | iUnicodeLevel = 1; 53 | 54 | Page *page = catalog->getPage(firstPage); 55 | double wid = page->getMediaWidth(); 56 | double ht = page->getMediaHeight(); 57 | 58 | /* 59 | int rot = page->getRotate(); 60 | fprintf(stderr, "Page rotation: %d\n", rot); 61 | if (rot == 90 || rot == 270) { 62 | double t = wid; 63 | wid = ht; 64 | ht = t; 65 | } 66 | */ 67 | 68 | const PDFRectangle *media = page->getMediaBox(); 69 | const PDFRectangle *crop = page->getCropBox(); 70 | 71 | fprintf(stderr, "MediaBox: %g %g %g %g (%g x %g)\n", 72 | media->x1, media->x2, media->y1, media->y2, wid, ht); 73 | fprintf(stderr, "CropBox: %g %g %g %g\n", 74 | crop->x1, crop->x2, crop->y1, crop->y2); 75 | 76 | writePS("\n"); 77 | writePS("\n"); 78 | writePSFmt("\n", 79 | PDFTOIPE_VERSION); 80 | writePS("\n"); 81 | writePSFmt("\n", 82 | wid, ht, crop->x2 - crop->x1, crop->y2 - crop->y1, 83 | crop->x1 - media->x1, crop->y1 - media->y1); 84 | writePS("\n"); 85 | writePS("18 0 0 18 0 0 e\n"); 86 | writePS("\n"); 87 | 88 | // initialize sequential page number 89 | seqPage = 1; 90 | } 91 | 92 | XmlOutputDev::~XmlOutputDev() 93 | { 94 | if (ok) { 95 | finishText(); 96 | writePS("\n"); 97 | } 98 | fclose(outputStream); 99 | } 100 | 101 | // ---------------------------------------------------------- 102 | 103 | void XmlOutputDev::setTextHandling(bool math, bool notext, 104 | bool literal, int mergeLevel, 105 | bool noTextSize, int unicodeLevel) 106 | { 107 | iIsMath = math; 108 | iNoText = notext; 109 | iIsLiteral = literal; 110 | iMergeLevel = mergeLevel; 111 | iNoTextSize = noTextSize; 112 | iUnicodeLevel = unicodeLevel; 113 | if (iUnicodeLevel >= 2) { 114 | writePS("\n"); 115 | writePS("\\usepackage[utf8]{inputenc}\n"); 116 | writePS("\n"); 117 | } 118 | } 119 | 120 | // ---------------------------------------------------------- 121 | 122 | void XmlOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) 123 | { 124 | writePSFmt("\n", pageNum, seqPage); 125 | fprintf(stderr, "Converting page %d (numbered %d)\n", 126 | seqPage, pageNum); 127 | writePS("\n"); 128 | ++seqPage; 129 | } 130 | 131 | void XmlOutputDev::endPage() 132 | { 133 | finishText(); 134 | writePS("\n"); 135 | } 136 | 137 | // -------------------------------------------------------------------- 138 | 139 | void XmlOutputDev::startDrawingPath() 140 | { 141 | finishText(); 142 | } 143 | 144 | void XmlOutputDev::stroke(GfxState *state) 145 | { 146 | startDrawingPath(); 147 | GfxRGB rgb; 148 | state->getStrokeRGB(&rgb); 149 | writeColor("getTransformedLineWidth()); 151 | 152 | double start; 153 | int length, i; 154 | #if POPPLER_VERSION_AT_LEAST(22, 9, 0) 155 | std::vector dash = state->getLineDash(&start); 156 | length = dash.size(); 157 | #else 158 | double *dash; 159 | state->getLineDash(&dash, &length, &start); 160 | #endif 161 | 162 | if (length) { 163 | writePS(" dash=\"["); 164 | for (i = 0; i < length; ++i) 165 | #if POPPLER_VERSION_AT_LEAST(22, 9, 0) 166 | writePSFmt("%g%s", state->transformWidth(dash.at(i)), 167 | (i == length-1) ? "" : " "); 168 | #else 169 | writePSFmt("%g%s", state->transformWidth(dash[i]), 170 | (i == length - 1) ? "" : " "); 171 | #endif 172 | writePSFmt("] %g\"", state->transformWidth(start)); 173 | } 174 | 175 | if (state->getLineJoin() > 0) 176 | writePSFmt(" join=\"%d\"", state->getLineJoin()); 177 | if (state->getLineCap()) 178 | writePSFmt(" cap=\"%d\"", state->getLineCap()); 179 | 180 | writePS(">\n"); 181 | doPath(state); 182 | writePS("\n"); 183 | } 184 | 185 | void XmlOutputDev::fill(GfxState *state) 186 | { 187 | startDrawingPath(); 188 | GfxRGB rgb; 189 | state->getFillRGB(&rgb); 190 | writeColor("\n"); 191 | doPath(state); 192 | writePS("\n"); 193 | } 194 | 195 | void XmlOutputDev::eoFill(GfxState *state) 196 | { 197 | startDrawingPath(); 198 | GfxRGB rgb; 199 | state->getFillRGB(&rgb); 200 | writeColor("\n"); 201 | doPath(state); 202 | writePS("\n"); 203 | } 204 | 205 | void XmlOutputDev::doPath(GfxState *state) 206 | { 207 | const GfxPath *path = state->getPath(); 208 | const GfxSubpath *subpath; 209 | int n, m, i, j; 210 | 211 | n = path->getNumSubpaths(); 212 | 213 | double x, y, x1, y1, x2, y2; 214 | for (i = 0; i < n; ++i) { 215 | subpath = path->getSubpath(i); 216 | m = subpath->getNumPoints(); 217 | state->transform(subpath->getX(0), subpath->getY(0), &x, &y); 218 | writePSFmt("%g %g m\n", x, y); 219 | j = 1; 220 | while (j < m) { 221 | if (subpath->getCurve(j)) { 222 | state->transform(subpath->getX(j), subpath->getY(j), &x, &y); 223 | state->transform(subpath->getX(j+1), subpath->getY(j+1), &x1, &y1); 224 | state->transform(subpath->getX(j+2), subpath->getY(j+2), &x2, &y2); 225 | writePSFmt("%g %g %g %g %g %g c\n", x, y, x1, y1, x2, y2); 226 | j += 3; 227 | } else { 228 | state->transform(subpath->getX(j), subpath->getY(j), &x, &y); 229 | writePSFmt("%g %g l\n", x, y); 230 | ++j; 231 | } 232 | } 233 | if (subpath->isClosed() && m>1) { 234 | writePS("h\n"); 235 | } 236 | } 237 | } 238 | 239 | // -------------------------------------------------------------------- 240 | 241 | void XmlOutputDev::updateTextPos(GfxState *) 242 | { 243 | if (iMergeLevel < 2) 244 | finishText(); 245 | } 246 | 247 | void XmlOutputDev::updateTextShift(GfxState *, double /*shift*/) 248 | { 249 | if (iMergeLevel < 1) 250 | finishText(); 251 | } 252 | 253 | void XmlOutputDev::drawChar(GfxState *state, double x, double y, 254 | double dx, double dy, 255 | double originX, double originY, 256 | CharCode code, int nBytes, 257 | const Unicode *u, int uLen) 258 | { 259 | // check for invisible text -- this is used by Acrobat Capture 260 | if ((state->getRender() & 3) == 3) 261 | return; 262 | 263 | // get the font 264 | if (!state->getFont()) 265 | return; 266 | 267 | if (iNoText) // discard text objects 268 | return; 269 | 270 | startText(state, x - originX, y - originY); 271 | 272 | if (uLen == 0) { 273 | if (code == 0x62) { 274 | // this is a hack to handle bullets created by pstricks and should 275 | // probably be an option 276 | writePS("\\ipesymbol{bullet}{}{}{}"); 277 | } else 278 | writePSFmt("[S+%02x]", code); 279 | } else { 280 | for (int i = 0; i < uLen; ++i) 281 | writePSUnicode(u[i]); 282 | } 283 | } 284 | 285 | void XmlOutputDev::startText(GfxState *state, double x, double y) 286 | { 287 | if (inText) 288 | return; 289 | 290 | double xt, yt; 291 | state->transform(x, y, &xt, &yt); 292 | 293 | const double *T = state->getTextMat(); 294 | const double *C = state->getCTM(); 295 | 296 | /* 297 | fprintf(stderr, "TextMatrix = %g %g %g %g %g %g\n", 298 | T[0], T[1], T[2], T[3], T[4], T[5]); 299 | fprintf(stderr, "CTM = %g %g %g %g %g %g\n", 300 | C[0], C[1], C[2], C[3], C[4], C[5]); 301 | */ 302 | 303 | double M[4]; 304 | M[0] = C[0] * T[0] + C[2] * T[1]; 305 | M[1] = C[1] * T[0] + C[3] * T[1]; 306 | M[2] = C[0] * T[2] + C[2] * T[3]; 307 | M[3] = C[1] * T[2] + C[3] * T[3]; 308 | 309 | GfxRGB rgb; 310 | state->getFillRGB(&rgb); 311 | writeColor("getFontSize()); 316 | writePS("valign=\"baseline\" "); 317 | writePSFmt("matrix=\"%g %g %g %g %g %g\">", M[0], M[1], M[2], M[3], xt, yt); 318 | 319 | if (iIsMath) 320 | writePS("$"); 321 | inText = true; 322 | } 323 | 324 | void XmlOutputDev::finishText() 325 | { 326 | if (inText) { 327 | if (iIsMath) 328 | writePS("$"); 329 | writePS("\n"); 330 | } 331 | inText = false; 332 | } 333 | 334 | // -------------------------------------------------------------------- 335 | 336 | void XmlOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, 337 | int width, int height, GfxImageColorMap *colorMap, 338 | bool interpolate, const int *maskColors, 339 | bool inlineImg) 340 | { 341 | finishText(); 342 | 343 | ImageStream *imgStr; 344 | unsigned char *p; 345 | GfxRGB rgb; 346 | int x, y; 347 | int c; 348 | 349 | writePSFmt("getCTM(); 352 | double tx = mat[0] + mat[2] + mat[4]; 353 | double ty = mat[1] + mat[3] + mat[5]; 354 | writePSFmt(" rect=\"%g %g %g %g\"", mat[4], mat[5], tx, ty); 355 | 356 | if (str->getKind() == strDCT && !inlineImg && 357 | 3 <= colorMap->getNumPixelComps() && colorMap->getNumPixelComps() <= 4) { 358 | // dump JPEG stream 359 | std::vector buffer; 360 | // initialize stream 361 | str = str->getNextStream(); 362 | str->reset(); 363 | // copy the stream 364 | while ((c = str->getChar()) != EOF) 365 | buffer.push_back(char(c)); 366 | str->close(); 367 | 368 | if (colorMap->getNumPixelComps() == 3) 369 | writePS(" ColorSpace=\"DeviceRGB\""); 370 | else 371 | writePS(" ColorSpace=\"DeviceCMYK\""); 372 | writePS(" BitsPerComponent=\"8\""); 373 | writePS(" Filter=\"DCTDecode\""); 374 | writePSFmt(" length=\"%d\"", buffer.size()); 375 | writePS(">\n"); 376 | 377 | for (unsigned int i = 0; i < buffer.size(); ++i) 378 | writePSFmt("%02x", buffer[i] & 0xff); 379 | 380 | #if 0 381 | } else if (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1) { 382 | // 1 bit depth -- not implemented in Ipe 383 | 384 | // initialize stream 385 | str->reset(); 386 | // copy the stream 387 | size = height * ((width + 7) / 8); 388 | for (i = 0; i < size; ++i) { 389 | writePSFmt("%02x", (str->getChar() ^ 0xff)); 390 | } 391 | str->close(); 392 | #endif 393 | } else if (colorMap->getNumPixelComps() == 1) { 394 | // write as gray level image 395 | writePS(" ColorSpace=\"DeviceGray\""); 396 | writePS(" BitsPerComponent=\"8\""); 397 | writePS(">\n"); 398 | 399 | // initialize stream 400 | imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), 401 | colorMap->getBits()); 402 | imgStr->reset(); 403 | 404 | // for each line... 405 | for (y = 0; y < height; ++y) { 406 | 407 | // write the line 408 | p = imgStr->getLine(); 409 | for (x = 0; x < width; ++x) { 410 | GfxGray gray; 411 | colorMap->getGray(p, &gray); 412 | writePSFmt("%02x", colToByte(gray)); 413 | p += colorMap->getNumPixelComps(); 414 | } 415 | } 416 | delete imgStr; 417 | 418 | } else { 419 | // write as RGB image 420 | writePS(" ColorSpace=\"DeviceRGB\""); 421 | writePS(" BitsPerComponent=\"8\""); 422 | writePS(">\n"); 423 | 424 | // initialize stream 425 | imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), 426 | colorMap->getBits()); 427 | imgStr->reset(); 428 | 429 | // for each line... 430 | for (y = 0; y < height; ++y) { 431 | 432 | // write the line 433 | p = imgStr->getLine(); 434 | for (x = 0; x < width; ++x) { 435 | colorMap->getRGB(p, &rgb); 436 | writePSFmt("%02x%02x%02x", 437 | colToByte(rgb.r), colToByte(rgb.g), colToByte(rgb.b)); 438 | p += colorMap->getNumPixelComps(); 439 | } 440 | } 441 | delete imgStr; 442 | } 443 | writePS("\n\n"); 444 | } 445 | 446 | // -------------------------------------------------------------------- 447 | 448 | struct UnicodeToLatex { 449 | int iUnicode; 450 | const char *iLatex; 451 | }; 452 | 453 | static const UnicodeToLatex unicode2latex[] = { 454 | // { 0xed, "{\\'\\i}" }, 455 | // -------------------------------------------------------------------- 456 | { 0xb1, "$\\pm$" }, 457 | { 0x391, "$\\Alpha$" }, 458 | { 0x392, "$\\Beta$" }, 459 | { 0x393, "$\\Gamma$" }, 460 | { 0x394, "$\\Delta$" }, 461 | { 0x395, "$\\Epsilon$" }, 462 | { 0x396, "$\\Zeta$" }, 463 | { 0x397, "$\\Eta$" }, 464 | { 0x398, "$\\Theta$" }, 465 | { 0x399, "$\\Iota$" }, 466 | { 0x39a, "$\\Kappa$" }, 467 | { 0x39b, "$\\Lambda$" }, 468 | { 0x39c, "$\\Mu$" }, 469 | { 0x39e, "$\\Nu$" }, 470 | { 0x39e, "$\\Xi$" }, 471 | { 0x39f, "$\\Omicron$" }, 472 | { 0x3a0, "$\\Pi$" }, 473 | { 0x3a1, "$\\Rho$" }, 474 | { 0x3a3, "$\\Sigma$" }, // sometimes \\sum would be better 475 | { 0x3a4, "$\\Tau$" }, 476 | { 0x3a5, "$\\Upsilon$" }, 477 | { 0x3a6, "$\\Phi$" }, 478 | { 0x3a7, "$\\Chi$" }, 479 | { 0x3a8, "$\\Psi$" }, 480 | { 0x3a9, "$\\Omega$" }, 481 | // -------------------------------------------------------------------- 482 | { 0x3b1, "$\\alpha$" }, 483 | { 0x3b2, "$\\beta$" }, 484 | { 0x3b3, "$\\gamma$" }, 485 | { 0x3b4, "$\\delta$" }, 486 | { 0x3b5, "$\\varepsilon$" }, 487 | { 0x3b6, "$\\zeta$" }, 488 | { 0x3b7, "$\\eta$" }, 489 | { 0x3b8, "$\\theta$" }, 490 | { 0x3b9, "$\\iota$" }, 491 | { 0x3ba, "$\\kappa$" }, 492 | { 0x3bb, "$\\lambda$" }, 493 | { 0x3bc, "$\\mu$" }, 494 | { 0x3be, "$\\nu$" }, 495 | { 0x3be, "$\\xi$" }, 496 | { 0x3bf, "$\\omicron$" }, 497 | { 0x3c0, "$\\pi$" }, 498 | { 0x3c1, "$\\rho$" }, 499 | { 0x3c3, "$\\sigma$" }, 500 | { 0x3c4, "$\\tau$" }, 501 | { 0x3c5, "$\\upsilon$" }, 502 | { 0x3c6, "$\\phi$" }, 503 | { 0x3c7, "$\\chi$" }, 504 | { 0x3c8, "$\\psi$" }, 505 | { 0x3c9, "$\\omega$" }, 506 | // -------------------------------------------------------------------- 507 | { 0x2013, "-" }, 508 | { 0x2019, "'" }, 509 | { 0x2022, "$\\bullet$" }, 510 | { 0x2026, "$\\cdots$" }, 511 | { 0x2190, "$\\leftarrow$" }, 512 | { 0x21d2, "$\\Rightarrow$" }, 513 | { 0x2208, "$\\in$" }, 514 | { 0x2209, "$\\not\\in$" }, 515 | { 0x2211, "$\\sum$" }, 516 | { 0x2212, "-" }, 517 | { 0x221e, "$\\infty$" }, 518 | { 0x222a, "$\\cup$" }, 519 | { 0x2260, "$\\neq$" }, 520 | { 0x2264, "$\\leq$" }, 521 | { 0x2265, "$\\geq$" }, 522 | { 0x22c5, "$\\cdot$" }, 523 | { 0x2286, "$\\subseteq$" }, 524 | { 0x25aa, "$\\diamondsuit$" }, 525 | // -------------------------------------------------------------------- 526 | // ligatures 527 | { 0xfb00, "ff" }, 528 | { 0xfb01, "fi" }, 529 | { 0xfb02, "fl" }, 530 | { 0xfb03, "ffi" }, 531 | { 0xfb04, "ffl" }, 532 | { 0xfb06, "st" }, 533 | // -------------------------------------------------------------------- 534 | }; 535 | 536 | #define UNICODE2LATEX_LEN (sizeof(unicode2latex) / sizeof(UnicodeToLatex)) 537 | 538 | void XmlOutputDev::writePSUnicode(int ch) 539 | { 540 | if (iIsLiteral && ch == '\\') { 541 | writePSChar(ch); 542 | return; 543 | } 544 | 545 | if (!iIsLiteral) { 546 | if (ch == '&' || ch == '$' || ch == '#' || ch == '%' 547 | || ch == '_' || ch == '{' || ch == '}') { 548 | writePS("\\"); 549 | writePSChar(ch); 550 | return; 551 | } 552 | if (ch == '<') { 553 | writePS("$<$"); 554 | return; 555 | } 556 | if (ch == '>') { 557 | writePS("$>$"); 558 | return; 559 | } 560 | if (ch == '^') { 561 | writePS("\\^{}"); 562 | return; 563 | } 564 | if (ch == '~') { 565 | writePS("\\~{}"); 566 | return; 567 | } 568 | if (ch == '\\') { 569 | writePS("$\\setminus$"); 570 | return; 571 | } 572 | } 573 | 574 | // replace some common Unicode characters 575 | if (1 <= iUnicodeLevel && iUnicodeLevel <= 2) { 576 | for (int i = 0; i < UNICODE2LATEX_LEN; ++i) { 577 | if (ch == unicode2latex[i].iUnicode) { 578 | writePS(unicode2latex[i].iLatex); 579 | return; 580 | } 581 | } 582 | } 583 | 584 | writePSChar(ch); 585 | } 586 | 587 | void XmlOutputDev::writePSChar(int code) 588 | { 589 | if (code == '<') 590 | writePS("<"); 591 | else if (code == '>') 592 | writePS(">"); 593 | else if (code == '&') 594 | writePS("&"); 595 | else if (code < 0x80) 596 | writePSFmt("%c", code); 597 | else { 598 | iUnicode = true; 599 | if (iUnicodeLevel < 2) { 600 | writePSFmt("[U+%x]", code); 601 | fprintf(stderr, "Unknown Unicode character U+%x on page %d\n", 602 | code, seqPage); 603 | } else { 604 | if (code < 0x800) { 605 | writePSFmt("%c%c", 606 | (((code & 0x7c0) >> 6) | 0xc0), 607 | ((code & 0x03f) | 0x80)); 608 | } else { 609 | // Do we never need to write UCS larger than 0x10000? 610 | writePSFmt("%c%c%c", 611 | (((code & 0x0f000) >> 12) | 0xe0), 612 | (((code & 0xfc0) >> 6) | 0x80), 613 | ((code & 0x03f) | 0x80)); 614 | } 615 | } 616 | } 617 | } 618 | 619 | void XmlOutputDev::writeColor(const char *prefix, const GfxRGB &rgb, 620 | const char *suffix) 621 | { 622 | if (prefix) 623 | writePS(prefix); 624 | writePSFmt("\"%f %f %f\"", colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b)); 625 | if (suffix) 626 | writePS(suffix); 627 | } 628 | 629 | void XmlOutputDev::writePS(const char *s) 630 | { 631 | fwrite(s, 1, strlen(s), outputStream); 632 | } 633 | 634 | void XmlOutputDev::writePSFmt(const char *fmt, ...) 635 | { 636 | va_list args; 637 | char buf[512]; 638 | 639 | va_start(args, fmt); 640 | vsprintf(buf, fmt, args); 641 | va_end(args); 642 | fwrite(buf, 1, strlen(buf), outputStream); 643 | } 644 | 645 | // -------------------------------------------------------------------- 646 | --------------------------------------------------------------------------------