Skip to content

Commit 1838896

Browse files
committed
Add ability to select default stream filter
Now you can change this in the preferences window. This will affect the streams created automatically by iText itself and the default filter used, when saving stream. You can still remove all filters afterward, if required.
1 parent 76ea5b5 commit 1838896

File tree

10 files changed

+210
-7
lines changed

10 files changed

+210
-7
lines changed

src/main/java/com/itextpdf/rups/RupsConfiguration.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.rups;
4444

45+
import com.itextpdf.brotlicompressor.BrotliStreamCompressionStrategy;
46+
import com.itextpdf.kernel.pdf.FlateCompressionStrategy;
47+
import com.itextpdf.kernel.pdf.IStreamCompressionStrategy;
48+
import com.itextpdf.kernel.pdf.PdfName;
4549
import com.itextpdf.rups.conf.LookAndFeelId;
4650
import com.itextpdf.rups.model.LoggerHelper;
4751
import com.itextpdf.rups.model.MruListHandler;
@@ -94,6 +98,7 @@ public enum RupsConfiguration {
9498
private static final String DEFAULT_HOME_VALUE = "home";
9599
private static final String CLOSE_OPERATION_KEY = "ui.closeoperation";
96100
private static final String DUPLICATE_OPEN_FILES_KEY = "rups.duplicatefiles";
101+
private static final String DEFAULT_FILTER_KEY = "rups.defaultfilter";
97102
private static final String HOME_FOLDER_KEY = "user.home";
98103
private static final String LOCALE_KEY = "user.locale";
99104
private static final String LOOK_AND_FEEL_KEY = "ui.lookandfeel";
@@ -132,6 +137,39 @@ public boolean canOpenDuplicateFiles() {
132137
return Boolean.parseBoolean(value);
133138
}
134139

140+
/**
141+
* Returns which default compression filter RUPS should use for streams.
142+
*
143+
* @return PdfName of the compression filter, or {@code null} if none.
144+
*/
145+
public PdfName getDefaultFilter() {
146+
final String value = getValueFromSystemPreferences(DEFAULT_FILTER_KEY);
147+
if (PdfName.FlateDecode.getValue().equals(value)) {
148+
return PdfName.FlateDecode;
149+
}
150+
if (PdfName.BrotliDecode.getValue().equals(value)) {
151+
return PdfName.BrotliDecode;
152+
}
153+
return null;
154+
}
155+
156+
/**
157+
* Returns which default compression filter strategy RUPS should use for streams.
158+
*
159+
* @return compression strategy for the default filter or {@code null} if
160+
* no compression required.
161+
*/
162+
public IStreamCompressionStrategy getDefaultFilterStrategy() {
163+
final String value = getValueFromSystemPreferences(DEFAULT_FILTER_KEY);
164+
if (PdfName.FlateDecode.getValue().equals(value)) {
165+
return new FlateCompressionStrategy();
166+
}
167+
if (PdfName.BrotliDecode.getValue().equals(value)) {
168+
return new BrotliStreamCompressionStrategy();
169+
}
170+
return null;
171+
}
172+
135173
/**
136174
* Returns the closing operation for the RUPS instance. Default it is returning EXIT_ON_CLOSE, but
137175
* another value could be useful when embedding RUPS or calling it from a Java process.
@@ -218,6 +256,18 @@ public void setOpenDuplicateFiles(boolean value) {
218256
this.temporaryProperties.setProperty(DUPLICATE_OPEN_FILES_KEY, Boolean.toString(value));
219257
}
220258

259+
/**
260+
* Sets which default compression filter RUPS should use for streams.
261+
*
262+
* @param value PdfName of the compression filter, or {@code null} if none.
263+
*/
264+
public void setDefaultFilter(PdfName value) {
265+
this.temporaryProperties.setProperty(
266+
DEFAULT_FILTER_KEY,
267+
value != null ? value.getValue() : "null"
268+
);
269+
}
270+
221271
/**
222272
* Sets the default folder to use in JFileChoosers.
223273
*
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2026 Apryse Group NV
4+
Authors: Apryse Software.
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU Affero General Public License version 3
8+
as published by the Free Software Foundation with the addition of the
9+
following permission added to Section 15 as permitted in Section 7(a):
10+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
11+
APRYSE GROUP. APRYSE GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
12+
OF THIRD PARTY RIGHTS
13+
14+
This program is distributed in the hope that it will be useful, but
15+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
or FITNESS FOR A PARTICULAR PURPOSE.
17+
See the GNU Affero General Public License for more details.
18+
You should have received a copy of the GNU Affero General Public License
19+
along with this program; if not, see http://www.gnu.org/licenses or write to
20+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
22+
http://itextpdf.com/terms-of-use/
23+
24+
The interactive user interfaces in modified source and object code versions
25+
of this program must display Appropriate Legal Notices, as required under
26+
Section 5 of the GNU Affero General Public License.
27+
28+
In accordance with Section 7(b) of the GNU Affero General Public License,
29+
a covered work must retain the producer line in every PDF that is created
30+
or manipulated using iText.
31+
32+
You can be released from the requirements of the license by purchasing
33+
a commercial license. Buying such a license is mandatory as soon as you
34+
develop commercial activities involving the iText software without
35+
disclosing the source code of your own applications.
36+
These activities include: offering paid services to customers as an ASP,
37+
serving PDFs on the fly in a web application, shipping iText with a closed
38+
source product.
39+
40+
For more information, please contact iText Software Corp. at this
41+
address: sales@itextpdf.com
42+
*/
43+
package com.itextpdf.rups.conf;
44+
45+
import com.itextpdf.kernel.pdf.PdfName;
46+
import com.itextpdf.rups.view.Language;
47+
48+
import java.util.Objects;
49+
50+
public class StreamFilterId {
51+
private final PdfName value;
52+
53+
public StreamFilterId(PdfName value) {
54+
this.value = value;
55+
}
56+
57+
public PdfName getValue() {
58+
return value;
59+
}
60+
61+
@Override
62+
public boolean equals(Object o) {
63+
if (o == null || getClass() != o.getClass()) {
64+
return false;
65+
}
66+
final StreamFilterId that = (StreamFilterId) o;
67+
return Objects.equals(value, that.value);
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return Objects.hashCode(value);
73+
}
74+
75+
@Override
76+
public String toString() {
77+
return value != null ? value.getValue() : Language.NONE.getString();
78+
}
79+
}

src/main/java/com/itextpdf/rups/model/PdfFile.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.rups.model;
4444

45-
import com.itextpdf.brotlicompressor.BrotliStreamCompressionStrategy;
4645
import com.itextpdf.kernel.exceptions.BadPasswordException;
46+
import com.itextpdf.kernel.pdf.CompressionConstants;
4747
import com.itextpdf.kernel.pdf.IStreamCompressionStrategy;
4848
import com.itextpdf.kernel.pdf.PdfDocument;
4949
import com.itextpdf.kernel.pdf.PdfReader;
5050
import com.itextpdf.kernel.pdf.PdfWriter;
5151
import com.itextpdf.kernel.pdf.ReaderProperties;
5252
import com.itextpdf.kernel.pdf.StampingProperties;
53+
import com.itextpdf.kernel.pdf.WriterProperties;
54+
import com.itextpdf.rups.RupsConfiguration;
5355
import com.itextpdf.rups.view.Language;
5456

5557
import java.io.ByteArrayInputStream;
@@ -254,7 +256,7 @@ private boolean openDocumentReadWrite(byte[] password) throws IOException {
254256
readerProperties
255257
);
256258
final ByteArrayOutputStream tempWriterOutputStream = new ByteArrayOutputStream();
257-
final PdfWriter writer = new PdfWriter(tempWriterOutputStream);
259+
final PdfWriter writer = new PdfWriter(tempWriterOutputStream, createWriterProperties());
258260
document = new PdfDocument(reader, writer, createStampingProps());
259261
writerOutputStream = tempWriterOutputStream;
260262
return true;
@@ -297,12 +299,21 @@ private boolean openDocumentReadOnly(byte[] password) throws IOException {
297299
}
298300
}
299301

302+
private static WriterProperties createWriterProperties() {
303+
final WriterProperties props = new WriterProperties();
304+
if (RupsConfiguration.INSTANCE.getDefaultFilter() == null) {
305+
props.setCompressionLevel(CompressionConstants.NO_COMPRESSION);
306+
}
307+
return props;
308+
}
309+
300310
private static StampingProperties createStampingProps() {
301311
final StampingProperties props = new StampingProperties();
302-
props.registerDependency(
303-
IStreamCompressionStrategy.class,
304-
new BrotliStreamCompressionStrategy()
305-
);
312+
final IStreamCompressionStrategy filterStrategy =
313+
RupsConfiguration.INSTANCE.getDefaultFilterStrategy();
314+
if (filterStrategy != null) {
315+
props.registerDependency(IStreamCompressionStrategy.class, filterStrategy);
316+
}
306317
return props;
307318
}
308319
}

src/main/java/com/itextpdf/rups/view/Language.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public enum Language {
186186
MENU_BAR_VERSION,
187187
MESSAGE_ABOUT,
188188

189+
NONE,
189190
NO_SELECTED_FILE,
190191
NULL_AS_TEXT,
191192

@@ -205,6 +206,7 @@ public enum Language {
205206
PLAINTEXT_DESCRIPTION,
206207
PREFERENCES,
207208
PREFERENCES_ALLOW_DUPLICATE_FILES,
209+
PREFERENCES_DEFAULT_STREAM_FILTER,
208210
PREFERENCES_NEED_RESTART,
209211
PREFERENCES_OPEN_FOLDER,
210212
PREFERENCES_RESET_TO_DEFAULTS,

src/main/java/com/itextpdf/rups/view/PreferencesWindow.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.rups.view;
4444

45+
import com.itextpdf.kernel.pdf.PdfName;
4546
import com.itextpdf.rups.RupsConfiguration;
4647
import com.itextpdf.rups.conf.LookAndFeelId;
48+
import com.itextpdf.rups.conf.StreamFilterId;
4749
import com.itextpdf.rups.view.icons.FrameIconUtil;
4850

4951
import java.awt.BorderLayout;
@@ -85,6 +87,7 @@ public final class PreferencesWindow {
8587

8688
// Fields to reset
8789
private JCheckBox openDuplicateFiles;
90+
private JComboBox<StreamFilterId> defaultFilter;
8891
private JTextField pathField;
8992
private JLabel restartLabel;
9093
private JComboBox<String> localeBox;
@@ -167,6 +170,21 @@ private void createGeneralSettingsTab() {
167170
JLabel openDuplicateFilesLabel = new JLabel(Language.PREFERENCES_ALLOW_DUPLICATE_FILES.getString());
168171
openDuplicateFilesLabel.setLabelFor(this.openDuplicateFiles);
169172

173+
this.defaultFilter = new JComboBox<>();
174+
this.defaultFilter.addItem(new StreamFilterId(null));
175+
this.defaultFilter.addItem(new StreamFilterId(PdfName.BrotliDecode));
176+
this.defaultFilter.addItem(new StreamFilterId(PdfName.FlateDecode));
177+
this.defaultFilter.setSelectedItem(new StreamFilterId(RupsConfiguration.INSTANCE.getDefaultFilter()));
178+
this.defaultFilter.addItemListener((ItemEvent e) -> {
179+
if (e.getStateChange() == ItemEvent.SELECTED) {
180+
RupsConfiguration.INSTANCE.setDefaultFilter(((StreamFilterId) e.getItem()).getValue());
181+
}
182+
});
183+
final JLabel defaultFilterLabel = new JLabel(
184+
Language.PREFERENCES_DEFAULT_STREAM_FILTER.getString()
185+
);
186+
defaultFilterLabel.setLabelFor(this.defaultFilter);
187+
170188
JPanel generalSettingsPanel = new JPanel();
171189
generalSettingsPanel.setLayout(this.gridBagLayout);
172190

@@ -176,6 +194,9 @@ private void createGeneralSettingsTab() {
176194
generalSettingsPanel.add(openDuplicateFilesLabel, this.left);
177195
generalSettingsPanel.add(this.openDuplicateFiles, this.right);
178196

197+
generalSettingsPanel.add(defaultFilterLabel, this.left);
198+
generalSettingsPanel.add(this.defaultFilter, this.right);
199+
179200
this.generalSettingsScrollPane = new JScrollPane(generalSettingsPanel);
180201
}
181202

@@ -270,6 +291,7 @@ private void completeJDialogCreation() {
270291
private void resetView() {
271292
this.pathField.setText(RupsConfiguration.INSTANCE.getHomeFolder().getPath());
272293
this.openDuplicateFiles.setSelected(RupsConfiguration.INSTANCE.canOpenDuplicateFiles());
294+
this.defaultFilter.setSelectedItem(new StreamFilterId(RupsConfiguration.INSTANCE.getDefaultFilter()));
273295
this.lookAndFeelBox.setSelectedItem(RupsConfiguration.INSTANCE.getLookAndFeel());
274296
this.localeBox.setSelectedItem(RupsConfiguration.INSTANCE.getUserLocale().toLanguageTag());
275297
this.restartLabel.setText(" ");

src/main/java/com/itextpdf/rups/view/itext/SyntaxHighlightedStreamPane.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ This file is part of the iText (R) project.
4747
import com.itextpdf.kernel.pdf.PdfStream;
4848
import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
4949
import com.itextpdf.rups.Rups;
50+
import com.itextpdf.rups.RupsConfiguration;
5051
import com.itextpdf.rups.controller.PdfReaderController;
5152
import com.itextpdf.rups.model.LoggerHelper;
5253
import com.itextpdf.rups.model.ObjectLoader;
@@ -224,7 +225,7 @@ public void saveToTarget() {
224225
PdfStreamUtil.setDataWithFilter(
225226
targetStream,
226227
baos.toByteArray(),
227-
null
228+
RupsConfiguration.INSTANCE.getDefaultFilterStrategy()
228229
);
229230
} catch (IOException e) {
230231
final String errorMessage = Language.ERROR_APPLYING_FILTER.getString();

src/main/resources/bundles/rups-lang.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ MENU_BAR_VERSION=Version
148148
149149
MESSAGE_ABOUT=RUPS is a tool by iText Group NV.\nIt uses iText, a Free Java-PDF Library.\nVisit http://www.itextpdf.com/ for more info.
150150
151+
NONE=None
151152
NO_SELECTED_FILE=No file selected.
152153
153154
NULL_AS_TEXT=null
@@ -173,6 +174,7 @@ PLAINTEXT_DESCRIPTION=Plain text representation of the PDF
173174
174175
PREFERENCES=Preferences
175176
PREFERENCES_ALLOW_DUPLICATE_FILES=Allow duplicate files in viewer
177+
PREFERENCES_DEFAULT_STREAM_FILTER=Default stream filter
176178
PREFERENCES_NEED_RESTART=RUPS needs to be restarted when changing this value.
177179
PREFERENCES_OPEN_FOLDER=Default Open File Folder
178180
PREFERENCES_RESET_TO_DEFAULTS=Reset to Defaults

src/main/resources/bundles/rups-lang_en_US.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ MENU_BAR_VERSION=Version
148148
149149
MESSAGE_ABOUT=RUPS is a tool by iText Group NV.\nIt uses iText, a Free Java-PDF Library.\nVisit http://www.itextpdf.com/ for more info.
150150
151+
NONE=None
151152
NO_SELECTED_FILE=No file selected.
152153
153154
NULL_AS_TEXT=null
@@ -173,6 +174,7 @@ PLAINTEXT_DESCRIPTION=Plain text representation of the PDF
173174
174175
PREFERENCES=Preferences
175176
PREFERENCES_ALLOW_DUPLICATE_FILES=Allow duplicate files in viewer
177+
PREFERENCES_DEFAULT_STREAM_FILTER=Default stream filter
176178
PREFERENCES_NEED_RESTART=RUPS needs to be restarted when changing this value.
177179
PREFERENCES_OPEN_FOLDER=Default Open File Folder
178180
PREFERENCES_RESET_TO_DEFAULTS=Reset to Defaults

src/main/resources/config/default.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
rups.duplicatefiles=false
2+
rups.defaultfilter=FlateDecode
23

34
ui.closeoperation=exit
45
ui.lookandfeel=flatlaflight

src/test/java/com/itextpdf/rups/RupsConfigurationTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.rups;
4444

45+
import com.itextpdf.brotlicompressor.BrotliStreamCompressionStrategy;
46+
import com.itextpdf.kernel.pdf.FlateCompressionStrategy;
47+
import com.itextpdf.kernel.pdf.PdfName;
48+
4549
import java.util.Set;
4650
import org.junit.jupiter.api.*;
4751

@@ -134,6 +138,35 @@ public void closingOperationsPossibleValuesTest() {
134138
Assertions.assertTrue(VALID_CLOSE_OPERATION_VALUES.contains(closeOperation));
135139
}
136140

141+
@Test
142+
void setDefaultFilterTest() {
143+
// Default is /FlateDecode
144+
Assertions.assertSame(
145+
PdfName.FlateDecode,
146+
RupsConfiguration.INSTANCE.getDefaultFilter()
147+
);
148+
Assertions.assertInstanceOf(
149+
FlateCompressionStrategy.class,
150+
RupsConfiguration.INSTANCE.getDefaultFilterStrategy()
151+
);
152+
// Changing to /BrotliDecode
153+
RupsConfiguration.INSTANCE.setDefaultFilter(PdfName.BrotliDecode);
154+
RupsConfiguration.INSTANCE.saveConfiguration();
155+
Assertions.assertSame(
156+
PdfName.BrotliDecode,
157+
RupsConfiguration.INSTANCE.getDefaultFilter()
158+
);
159+
Assertions.assertInstanceOf(
160+
BrotliStreamCompressionStrategy.class,
161+
RupsConfiguration.INSTANCE.getDefaultFilterStrategy()
162+
);
163+
// Changing to an unsupported value, should return null
164+
RupsConfiguration.INSTANCE.setDefaultFilter(PdfName.ASCIIHexDecode);
165+
RupsConfiguration.INSTANCE.saveConfiguration();
166+
Assertions.assertNull(RupsConfiguration.INSTANCE.getDefaultFilter());
167+
Assertions.assertNull(RupsConfiguration.INSTANCE.getDefaultFilterStrategy());
168+
}
169+
137170
@AfterAll
138171
public static void afterClass() {
139172
RupsConfiguration.INSTANCE.restore(copy);

0 commit comments

Comments
 (0)