Compdigitec Labs

ImageMagick snippet: batch crop, dither, and guillotine

By admin | November 12, 2020

# Create output dirs
mkdir -p cropped dithered output
rm cropped/*.png dithered/*.png output/*.png

# Crop (3000x2000 at position 200, 200)
mogrify -crop 3000x2000+200+200 -path ./cropped *.png

# Dither (to indexed colours)
mogrify +dither -colors 4 -path ./dithered cropped/*.png

# Guillotine
mogrify -crop 2x1@ +repage -path ./output dithered/*.png

Topics: Linux, Uncategorized | No Comments »

Concatenating PDFs while padding/extending odd-length PDFs

By admin | October 10, 2020

When concatenating PDFs to consolidate print jobs, it is nice to have single-page or PDFs with odd numbers of pages to not have to share sides with another unrelated document.

There is a short script available at ; however, it does not appear to be updated for PyPDF2. So here is an update for Python3 and PyPDF2.


sudo apt install python3-pypdf2

#!/usr/bin/env python3
# Inspired from

import copy
import sys
from PyPDF2 import PdfFileWriter, PdfFileReader

def main():
    if len(sys.argv) < 2:
        print("No input PDFs specified", file=sys.stderr)
        return 1

    pdf_writer = PdfFileWriter()
    output_page_number = 0
    alignment = 2           # to align on even pages

    # So we can close the file objects later.
    file_objects = []

    for filename in sys.argv[1:]:
        # Store the file object for closing
        f = open(filename, 'rb')

        # Open the input PDF
        pdf_reader = PdfFileReader(f)

        # Add input pages
        for page in pdf_reader.pages:
            output_page_number += 1

        # Add filler pages
        while output_page_number % alignment != 0:
            output_page_number += 1

    # Write output PDF while input files are still open.

    # Close open files.
    while len(file_objects) > 0:

    return 0


Topics: Linux | No Comments »

Scanning with Brother DCP-7065DN in Ubuntu

By admin | September 12, 2020

First, make sure the printer is detected in lsusb:

$ lsusb | grep Brother
Bus 001 Device 011: ID 04f9:024a Brother Industries, Ltd 

Then, either add a udev rule to ensure that we have permission to access it, or use the following one-time hack:

sudo chmod 777 /dev/bus/usb/001/011

Now, install the correct driver for the printer from For the DCP-7065DN on Ubuntu 64-bit, the following package worked:

5937473842d95571b0d8ff50d6095198 brscan4-0.4.9-1.amd64.deb

Check that sane-find-scanner can see it:

$ sane-find-scanner
# sane-find-scanner will now attempt to detect your scanner. If the
# result is different from what you expected, first make sure your
# scanner is powered up and properly connected to your computer.

# No SCSI scanners found. If you expected something different, make sure that
# you have loaded a kernel SCSI driver for your SCSI adapter.

found USB scanner (vendor=0x04f9, product=0x024a) at libusb:001:011
# Your USB scanner was (probably) detected. It may or may not be supported by
# SANE. Try scanimage -L and read the backend's manpage.

# Not checking for parallel port scanners.

# Most Scanners connected to the parallel port or other proprietary ports
# can't be detected by this program.

# You may want to run this program as root to find all devices. Once you
# found the scanner devices, be sure to adjust access permissions as
# necessary.

Finally, check that scanimage can see it. If this succeeds, then the scanner is operational (and can be used from Simple Scan or any other scan software).

$ scanimage -L
device `brother4:bus1;dev4' is a Brother DCP-7065DN USB scanner

Topics: Linux | No Comments »

Simple recursive DNS server with Unbound DNS

By admin | July 30, 2020

This is a simple configuration for running a recursive DNS server (passes DNS requests to another server and caches responses) with the Unbound DNS server.

Installation (Ubuntu):

sudo apt-get install -y unbound

Open the config

sudo vim /etc/unbound/unbound.conf


Replace below with the desired upstream DNS server.

# The following line includes additional configuration files from the
# /etc/unbound/unbound.conf.d directory.
#include: "/etc/unbound/unbound.conf.d/*.conf"
# NOTE: needed to comment out the above line avoid a "status: SERVFAIL" response

    # Enable verbose debugging messages
    verbosity: 1000

    # Run on all interfaces

    # Hide the server name and version
    hide-identity: yes
    hide-version: yes

    # Who should be able to query the server
    access-control: allow

    do-ip4: yes
    do-ip6: no

    do-udp: yes
    # Enable this to support TCP DNS which is required in some applications
    do-tcp: yes

    # Allow forwarding to another DNS server (e.g. another local dnsmasq or systemd-resolve)
    do-not-query-localhost: no

    name: "."
    # Replace with your desired upstream DNS server
    # You can have multiple forward-addr lines

Starting the server

sudo systemctl restart unbound

Debugging / Troubleshooting

Query the server

dig @your_server_here

Read the DNS server log

sudo systemctl status unbound -n 50


Topics: Linux | No Comments »

Generating POT files for WordPress plugins

By admin | July 6, 2020

The easiest non-GUI way appears to be using WP CLI.

Run the following in the plugin folder:

wp i18n make-pot . output.pot

Topics: HTTP (Internet) | No Comments »

Make fails silently

By admin | February 28, 2017

Run make <...> -d &> log.txt and examine the log. Likely there is some prerequisite which is missing, in the form of “File `foo’ does not exist.”

Topics: Linux | No Comments »

LaTeX macros ending in numbers

By admin | February 13, 2016

Only letters are directly permitted in macro names, but by using csname to create definitions along with a variable command, we can simulate them.

First, define the macros with numbers using \csname:

\expandafter\def\csname xR1\endcsname{-3}
\expandafter\def\csname xR2\endcsname{9}

Now, create a command which takes in one variable argument, and simply expands it to call the appropriate macro (“xR” + variable) defined above.

\newcommand{\xR}[1]{\expandafter\csname xR#1\endcsname}

And to use the macros:

The first is \xR1 and the second is \xR2.

Topics: Linux | No Comments »

Phabricator LDAP (and other) account integration table

By admin | January 17, 2016


See also

For LDAP, the following structure is used:

Topics: PHP | No Comments »

Possible crash in method_exists() with PHP 5.3

By admin | August 9, 2014

Apparently in some versions of PHP 5.3, calling method_exists() on a class which doesn’t exist seems to cause a crash. The solution, seen here, apparently involves checking class_exists() to prevent a potentially crashing call to method_exists().

This particular bug was causing the administration page of the MathJax-LaTeX WordPress plugin to be blank in the admin interface.

The trick is to replace the two lines in mathjax-latex-admin.php lines 91-92:

$wp_latex_disabled = method_exists('WP_LaTeX','init') ? "disabled='true'" : "";
$wp_latex_disabled_warning = method_exists('WP_LaTeX','init') ? "Disable wp-latex to use this syntax." : "";


$wp_latex_disabled = (class_exists('WP_LaTeX', false) && method_exists('WP_LaTeX','init')) ? "disabled='true'" : "";
$wp_latex_disabled_warning = (class_exists('WP_LaTeX', false) && method_exists('WP_LaTeX','init')) ? "Disable wp-latex to use this syntax." : "";

Topics: PHP | No Comments »

Disable dragging of an element in JSXGraph

By admin | July 20, 2014

Set the attribute ‘fixed‘ to true in JXG.GeometryElement:

var line = board.create('line', [ [0,0], [1,1] ], {dash:0, strokeColor:"#FF0000", strokeWidth:3, fixed: true});


var line = board.create('line', [ [0,0], [1,1] ], {dash:0, strokeColor:"#FF0000", strokeWidth:3});
line.setAttribute({ fixed: true });

Topics: (X)HTML, Windows | No Comments »

If you found this article helpful or interesting, please help Compdigitec spread the word. Don’t forget to subscribe to Compdigitec Labs for more useful and interesting articles! « Older Entries