Today I had a situation where I needed to combine two PDF files into one. PDF Split and Merge is a free excellent program for both splitting and merging PDF files. This program allows you to split a PDF files according to a large number of criteria (see screen shot for all options) , as well as merge several PDF files into a single file.
PDF Split and Merge is available for download here. For use on Linux systems download the Zip archive. Though this post focuses on the Linux version, PDF Split and Merge is also available for windows and mac as well.
Once you’ve downloaded the program extract the contents of the zip file, by double clicking the Zip file and selecting “Extract.”
Once the files have been extracted there are two different ways to run the program. The first is to right click the pdfsam-1.1.0.jar file and select “Open with Sun Java 6 Runtime.” If you do not have that option in your right-click menu follow the steps below.
Open a terminal and change to the directory containing the extracted files and run:
java -jar pdfsam-1.1.0.jar
The program will open and you will be ready to split/merge your PDFs!
-
-
Merge
-
-
Split Options
Exceptional Code Comments
The code below is not exceptional in itself…however, the comments that were provided by a friend are extremely exceptional and well worth the read!
* Student Name: Benaiah Henry
* Course: COSC 4303
* Package: Server
* File name: ConnectionHandler.java
*
* Purpose:
*
* Development Computer: Dell Dimenstion E520
* Operating System: Ubuntu 9.10
* Integrated Development Environment (IDE): Netbeans IDE 6.7.1
* Compiler: javac
**************************************************************/
import java.net.*;
import java.io.*;
import java.util.*;
/**
* This handles the connection (not MANAGE, HANDLE) Management is an entirely
* different class which probably involves lots of pointy ears, walking around,
* and looking for the token ring under the desk (it’s very small and hard to
* find). But that’s not this class.
*
* This class is more like Dogbert. It smacks you upside the head, tells you
* things you need to know but won’t listen to, and walks away with the money.
* That’s what happens when we throw an exception here – Dogbert takes the money.
* @author Benaiah Henry
*/
public class ConnectionHandler {
ServerSocket serverSocket;
ResultHandler resultHandler;
String serverIP;
ArrayList<ConnectedUser> connectedUsers;
//ArrayList<ServerSocket> serverSockets;
public static final int DEFAULT_PORT = 1234;
public static final int MAX_CLIENTS = 500;
public static final int ACCEPT_TIMEOUT_LENGTH = 10;
public static final int SHORT_STRING = 32;
/**
*
* @throws java.io.IOException
*/
public ConnectionHandler(ResultHandler resultH) {
resultHandler = resultH;
try {
connectedUsers = new ArrayList<ConnectedUser>();
//serverSockets = new ArrayList<ServerSocket>();
InetAddress localIP = InetAddress.getLocalHost();
serverIP = localIP.getHostAddress();
serverSocket = new ServerSocket(DEFAULT_PORT, MAX_CLIENTS);
serverSocket.setSoTimeout(5);
} catch (IOException e) {
System.err.println(“Failed to create ServerSocket”);
} // End Try/Catch
} // End Constructor
/*
* Have you ever been bothered by how none of the clocks anywhere agree
* with each other? Have you ever just wanted a short little method
* that would synchronize everything? That would just update and make
* standardized time work? Yes we can!
* But this is not that method…
*/
//**************************************************************/
/**
* Checks for new data from all clients
*/
public void update() {
ConnectedUser temp = null;
for (int i = 0; i < connectedUsers.size(); i++) {
temp = connectedUsers.get(i);
readFromClient(temp.getSocket(), temp.getDataInputStream(), temp.getDataOutputStream(), i);
} // End for
} // End update
//**************************************************************/
/**
* Checks a serverSocket for new client connections
* And Asks accounting department to cut check to our wonderful clients
*
*/
public void checkForClients() {
DataOutputStream out;
DataInputStream in;
Socket connection;
InetAddress tempIP;
String IP;
try {
connection = serverSocket.accept();
//connection.getChannel().configureBlocking(false);
//System.err.println(“after connection made”);
in = new DataInputStream(connection.getInputStream());
out = new DataOutputStream(connection.getOutputStream());
tempIP = connection.getInetAddress();
IP = tempIP.toString();
//System.err.println(“after ip string”);
// create a new user ex nihilo
connectedUsers.add(new ConnectedUser(IP, null, connection, in, out));
//System.err.println(“after add user”);
} catch (SocketTimeoutException e) {
System.err.println(“accept timeout – continuing execution”);
} catch (IOException e) {
System.err.println(“socket accept failed”);
} // End Try/Catch
} // End checkForClients
//**************************************************************/
/**
*
* @param connection The socket to read from
* @param in The DataInputStream of the connection
* @param out The DataOutputStream of the connection
* @param index Index of the client to read from
*/
public void readFromClient(Socket connection, DataInputStream in, DataOutputStream out, int index) {
int msgTypeID;
try {
connection.setSoTimeout(5);
msgTypeID = in.readInt();
switch (msgTypeID) {
case 100:
process100(in, index);
break;
case 300:
process300(in, index);
break;
case 900:
process900(index, connection, in, out);
break;
default:
System.err.println(“Invalid message code”);
break;
} // End switch
} catch (IOException e) {
System.err.println(“No data from client”);
} // End Try/Catch
}// End readFromClient
/**
* The wonderful processing method
* @param in A DataInputStream
* @param index Index of client
*/
private void process100(DataInputStream in, int index) {
String alias = null;
byte[] temp = new byte[SHORT_STRING];
try {
for (int i = 0; i < SHORT_STRING; i++) {
temp[i] = in.readByte();
}
alias = new String(temp).trim();
connectedUsers.get(index).setAlias(alias);
System.out.println(alias);
} catch (IOException e) {
System.err.println(“Failed to process 100 message”);
}
}
/**
* The other wonderful processing method, but 3 times better than the first one
* @param in A DataInputStream
* @param index Client index
*/
private void process300(DataInputStream in, int index) {
int questionNum = 0;
boolean didAnswer = false; // yes, I know this is bad grammar
int timeTaken = 0; // careful, there will be problems if the user takes longer than 49,710 days to answer
// if you think that’s too long, consider using ‘long’
String answer = null;
byte[] temp = new byte[SHORT_STRING];
try {
questionNum = in.readInt();
didAnswer = in.readBoolean();
timeTaken = in.readInt();
for (int i = 0; i < SHORT_STRING; i++) {
temp[i] = in.readByte();
} // End for
answer = new String(temp).trim();
} catch (Exception e) {
System.err.println(“Failed to process 300 message”);
} // End Try/catch
resultHandler.storeAnswer(questionNum, didAnswer, timeTaken, answer, connectedUsers.get(index).getIPAddress());
} // End process300
/*
* Some of you may be wondering why process900 sends 999. Let me explain:
* Process 0 was created.
* process 0 begot process 100. Process 0 lived for
* 425 seconds and had other sons and daughters.
* Process 100 begot process 200. Process 100 lived for
* 511 seconds and had other sons and daughters.
* Process 200 begot process 300. Process 200 lived for
* 441 seconds and had other sons and daughters.
* Process 300 begot process 400. Process 300 lived for
* 225 seconds and had other sons and daughters.
* Process 400 begot process 500. Process 500 lived for
* 311 seconds and had other sons and daughters.
* Process 500 begot process 600. Now process 500 lived in the days of
* Windows ME. Dark were the times, and wild ran the memory manager.
* Process 500 lived 23 seconds and had no other children. Then it seg-faulted.
* Process 600 begot process 700. Process 600 lived for
* 259 seconds and had other sons and daughters.
* Process 700 begot process 800, who was lost in the upgrade to Vista.
* Process 700 begot process 900 (after confirming “allow” 71942 times.
* Children can be quite a security risk). Process 700 lived for
* 111 seconds and had other sons and daughters.
*
* Now process 900 walked with the kernel, and had many sons
* and daughters. It was granted a large memory footprint, and the
* exclusive use of 2 CPU cores, plus direct access to the PCI bus.
* Having so much wealth to manage, Process 900 diligently instructed
* his children, giving to some 10mb, to other 100mb, and to some whole
* gigabytes of memory. Thus was process 999, son of process 900,
* alloted communication with the first 13 pins of the card in 2nd PCI
* slot (which happens to be the NIC), and is thus responsible for
* for sending poetry, free chicken sandwich coupons, and instructions
* on building to-scale parking garages on the kitchen table without
* creating multi-car pileups.
*/
//**************************************************************/
/**
*
* Closes the connections
* @param index Index of client to close connections for
* @param connection The socket of the client
* @param in DataInputStream of connection
* @param out DataOutputStream of connection
*/
private void process900(int index, Socket connection, DataInputStream in, DataOutputStream out) {
send999(connectedUsers.get(index).getAlias(), out);
try {
in.close();
out.close();
connection.close();
} catch (Exception e) {
System.err.printf(“Failed to close connection for client at IP address: %s”, connection.getInetAddress().toString());
} // End Try/Catch
} // End process900
//**************************************************************/
/**
* Send Connection has been closed
* @param alias Username of client
* @param out DataOutputStream of client
*/
private void send999(String alias, DataOutputStream out) {
try {
out.writeInt(999);
writeString(alias, SHORT_STRING, out);
} catch (IOException e) {
System.err.println(“Failed to send 999 message”);
} // End Try/Catch
} // End send999
/**
* Writes strings to a DataOutputStream. Either truncates at size, or pads with 0’s to size.
*
* Cutting a string would be more fun, but such is life
*
* @param s
* @param size
* @param out
*/
private void writeString(String s, int size, DataOutputStream out) {
try {
if (s.length() < (size – 1)) {
out.writeBytes(s);
for (int i = 0; i < (size – s.length()); i++) {
out.writeByte(0);
} // End for
} else if (s.length() > (size – 1)) {
s = s.trim().substring(0, (size – 1));
out.writeBytes(s);
out.writeByte(0);
} else {
out.writeBytes(s);
out.writeByte(0);
} // End if/else if/else
} catch (IOException e) {
System.err.println(“Write failed”);
System.exit(-1);
} // End Try/Catch
} // End writeString
//**************************************************************/
/**
* Send the question to all clients
* @param questionNum Number of the question
* @param questionType Type of question as an int
* @param timeLimit Time limit on question
* @param tallyMode Force tally mode
* @param optionCount Number of answer options
* @param questionText The question
* @param answerOptions All answer options concatenated and separated by ascii “04″
*/
public void sendQuestion(int questionNum, int questionType, int timeLimit, boolean tallyMode, int optionCount, String questionText, String answerOptions) {
ConnectedUser temp = null;
DataOutputStream out;
try {
for (int i = 0; i < connectedUsers.size(); i++) {
temp = connectedUsers.get(i);
out = temp.getDataOutputStream();
out.writeInt(200);
out.writeInt(questionNum);
out.writeInt(questionType);
out.writeInt(timeLimit);
out.writeBoolean(tallyMode);
out.writeInt(optionCount);
writeString(questionText, 256, out);
writeString(answerOptions, 256, out);
} // End for
} catch (IOException e) {
System.err.printf(“Failed to send 200 message to IP address %s”, temp.getSocket().getInetAddress().toString());
} // End Try/Catch
} // End SendQuestion
//The llama in the sky has recieved your request
//but your question is judged as causing unrest
//the words are malicious
//puncuation sadicious
//we’ll have to correct for success
//**************************************************************/
/**
* Send the correct answer to clients
* @param isCorrect Whether the answer was correct
* @param timeTaken How long it took to answer
* @param submittedAnswer Client’s submitted answer
* @param correctAnswer Correct answer
*/
public void sendGradedQuestion(boolean isCorrect, int timeTaken, String submittedAnswer, String correctAnswer) {
ConnectedUser temp = null;
DataOutputStream out;
try {
for (int i = 0; i < connectedUsers.size(); i++) {
temp = connectedUsers.get(i);
out = temp.getDataOutputStream(); //check for actual function name
//we sent a 400 (I don’t know why)
//I would have chosen 3,4, or pi
//but no one asked me
//or revealed the design
//no diagrams, no tree
//(they charged a $10 fine)
out.writeInt(400);
out.writeBoolean(isCorrect);
out.writeInt(timeTaken);
writeString(submittedAnswer, 32, out);
writeString(correctAnswer, 32, out);
} // End for
} catch (IOException e) {
System.err.println(“Failed to send 400 message to all clients”);
} // End Try/Catch
}// End sendGradedQuestion
//**************************************************************/
/**
* Send notification of end of set to all clients
*/
public void sendEndOfSet() {
ConnectedUser temp = null;
DataOutputStream out;
try {
for (int i = 0; i < connectedUsers.size(); i++) {
temp = connectedUsers.get(i);
out = temp.getDataOutputStream();
out.writeInt(500);
} // End for
} catch (IOException e) {
System.err.println(“Failed to send 500 message to all clients”);
} // End Try/Catch
}// End sendEndOfSet
//**************************************************************/
public String getServerIP() {
return serverIP;
} // End getServerIP
//**************************************************************/
public int getConnectedUserCount() {
return connectedUsers.size();
} // End getConnectedUserCount
}// End ConnectionHandler