1.5修复版本

This commit is contained in:
souno
2023-06-15 13:21:35 +08:00
commit 8b2e038551
25 changed files with 4496 additions and 0 deletions

72
.gitignore vendored Normal file
View File

@@ -0,0 +1,72 @@
out/
.DS_Store
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/artifacts/StegSolve.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<component name="ArtifactManager">
<artifact type="jar" build-on-make="true" name="StegSolve">
<output-path>$PROJECT_DIR$/out/artifacts/StegSolve</output-path>
<root id="archive" name="StegSolve.jar">
<element id="directory" name="META-INF">
<element id="file-copy" path="$PROJECT_DIR$/META-INF/MANIFEST.MF" />
</element>
<element id="module-output" name="stegsolve" />
<element id="library" level="project" name="flatlaf-3.1.1" />
</root>
</artifact>
</component>

9
.idea/artifacts/stegsolve_jar.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<component name="ArtifactManager">
<artifact type="jar" name="stegsolve:jar">
<output-path>$PROJECT_DIR$/out/artifacts/stegsolve_jar</output-path>
<root id="archive" name="stegsolve.jar">
<element id="module-output" name="stegsolve" />
<element id="extracted-dir" path="$USER_HOME$/Desktop/flatlaf-3.1.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

6
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="jbrsdk_jcef-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/stegsolve.iml" filepath="$PROJECT_DIR$/stegsolve.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

3
META-INF/MANIFEST.MF Normal file
View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: stegsolve.StegSolve

11
README.md Normal file
View File

@@ -0,0 +1,11 @@
# StegSolve
A modifed version of stegsolve
## 1.4 changes
- Added zoom to image
- Added drag&drop zone for files
- Added "all" option to channel planes in "Data Extract"
- Added horizontal scrolling (Shift+Mousewheel)

20
Updates.txt Normal file
View File

@@ -0,0 +1,20 @@
Version 1.4
- Added zoom to image
- Added drag&drop zone for files
- Added "all" option to channel planes in "Data Extract"
- Added horizontal scrolling (Shift+Mousewheel)
Version 1.3
1. Added a transform showing only the gray bits of an image.
2. CRC checks on PNGs now done, and correct CRC shown if wrong.
3. Image combiner added
4. Dialogs, etc are now resizable
Version 1.2
Minor bug updates, previous version broke the frame browser
Version 1.1
1. added left and right arrow keys to main screen, frame viewer and
stereo transform to control left and right buttons.
2. scrollbars added to frame browser, stereogram solver and main panel.

BIN
flatlaf-3.1.1.jar Normal file

Binary file not shown.

12
stegsolve.iml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="flatlaf-3.1.1" level="project" />
</component>
</module>

99
stegsolve/AboutFrame.java Normal file
View File

@@ -0,0 +1,99 @@
/*
* aboutFrame.java
*
* Created on 18-Apr-2011, 09:12:05
*/
package stegsolve;
/**
* Just a small about box with some details of the
* application
* @author Caesum
*/
public class AboutFrame extends javax.swing.JFrame {
/** Creates new form aboutFrame */
public AboutFrame() {
initComponents();
jEditorPane1.setCaretPosition(0);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
okButton = new javax.swing.JButton();
aboutPanel = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
jEditorPane1 = new javax.swing.JEditorPane();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
okButton.setText("OK");
okButton.setAlignmentX(0.5F);
okButton.addActionListener(this::okButtonActionPerformed);
aboutPanel.setPreferredSize(new java.awt.Dimension(450, 300));
jEditorPane1.setContentType("text/html");
jEditorPane1.setEditable(false);
jEditorPane1.setText("<html>\n<center><b>Stegsolve v1.5 by Souno Inherited in Caesum<br>Mod by Giotino</b></center>\n<br>\nStegsolve is a stegano solver for challenges. It provides these main functions:\n<ul>\n<li>A quick view of different bit planes and some simple transformations.</li>\n<li>Data extraction from planes. This can be row order or column order, with bits treated as a bitstream and converted into bytes.</li>\n<li>Some simple checking of file formats and reporting on the filesize, additional bytes, file holes, etc. This is highly dependent upon the type of image.</li>\n<li>Stereogram solver - simply change the offset until the image becomes visible.</li>\n<li>Frame browser for animated images. This should also work for viewing layers in multi-layered PNG files.</li>\n<li>Image combiner to combine two images in a variety of ways and browse through the different combinations.</li>\n</ul>\n<p>Copy/Cut and paste is available from most text using CTRL-C to copy, CTRL-V to paste and CTRL-X for cut.\n<p>If an image fails to load, for example because it is corrupt, then file analysis will still open the file that you just tried to view. It may, however, crash out before reporting the information that you want to know. This will work though on images where the PNG has corrupted CRC values for example.\n</html>\n");
jEditorPane1.setMinimumSize(new java.awt.Dimension(150, 150));
jEditorPane1.setPreferredSize(new java.awt.Dimension(150, 150));
jScrollPane1.setViewportView(jEditorPane1);
javax.swing.GroupLayout aboutPanelLayout = new javax.swing.GroupLayout(aboutPanel);
aboutPanel.setLayout(aboutPanelLayout);
aboutPanelLayout.setHorizontalGroup(
aboutPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 444, Short.MAX_VALUE)
);
aboutPanelLayout.setVerticalGroup(
aboutPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 311, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(168, 168, 168)
.addComponent(okButton)
.addContainerGap(227, Short.MAX_VALUE))
.addComponent(aboutPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 444, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(aboutPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 311, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(okButton)
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
/**
* Disposes of the form when the ok button is pressed
* @param evt Button event
*/
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
dispose();
}//GEN-LAST:event_okButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel aboutPanel;
private javax.swing.JEditorPane jEditorPane1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton okButton;
// End of variables declaration//GEN-END:variables
}

View File

@@ -0,0 +1,232 @@
/*
* CombineTransform.java
*/
package stegsolve;
import java.awt.image.*;
/**
* Represents combination of two images
* @author Caesum
*/
public class CombineTransform {
/**
* Original images
*/
private BufferedImage im1, im2;
/**
* Transformed image
*/
private BufferedImage transform;
/**
* Number of transformation
*/
private int transNum;
private final int NUMTRANS = 13;
/**
* Create a new transformation
* @param bi Image 1
* @param bi2 Image 2
*/
CombineTransform(BufferedImage bi, BufferedImage bi2)
{
im1 = bi;
im2 = bi2;
transNum=0;
calcTrans();
}
/**
* interlaces the images
*/
private void calcInterlace()
{
int width = im1.getWidth();
if(im2.getWidth()<width) width = im2.getWidth();
int height = im1.getHeight();
if(im2.getHeight()<height) height = im2.getHeight();
if(transNum==11)
{
transform = new BufferedImage(width, 2*height, BufferedImage.TYPE_INT_RGB);
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
{
transform.setRGB(i, j*2, im1.getRGB(i,j));
transform.setRGB(i, j*2+1, im2.getRGB(i,j));
}
}
else if(transNum == 12)
{
transform = new BufferedImage(2*width, height, BufferedImage.TYPE_INT_RGB);
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
{
transform.setRGB(i*2, j, im1.getRGB(i,j));
transform.setRGB(i*2+1, j, im2.getRGB(i,j));
}
}
}
/**
* Combine the images
*/
private void calcTrans()
{
if(transNum==11||transNum==12)
{
calcInterlace();
return;
}
int width = im1.getWidth();
if(im2.getWidth()>width) width = im2.getWidth();
int height = im1.getHeight();
if(im2.getHeight()>height) height = im2.getHeight();
transform = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
{
int col1=0;
int col2=0;
if(i<im1.getWidth()&&j<im1.getHeight())
col1 = im1.getRGB(i,j);
if(i<im2.getWidth()&&j<im2.getHeight())
col2 = im2.getRGB(i,j);
int col = comb(col1,col2);
transform.setRGB(i, j, col);
}
}
/**
* Reduce the offset and try to solve
*/
public void back()
{
transNum--;
if(transNum<0) transNum=NUMTRANS-1;
calcTrans();
}
/**
* Increase the offset and try to solve
*/
public void forward()
{
transNum++;
if(transNum>=NUMTRANS) transNum=0;
calcTrans();
}
/**
* Combines two colours according to transform
* @param c1 colour 1
* @param c2 colour 2
* @return combined colour
*/
private int comb(int c1, int c2)
{
int r,g,b;
switch(transNum)
{
case 0:
return c1^c2;
case 1:
return c1|c2;
case 2:
return c1&c2;
case 3:
return c1+c2;
case 4:
r = ((c1&0xff0000)+(c2&0xff0000))&0xff0000;
g = ((c1&0xff00)+(c2&0xff00))&0xff00;
b = ((c1&0xff)+(c2&0xff))&0xff;
return r|g|b;
case 5:
return c1-c2;
case 6:
r = ((c1&0xff0000)-(c2&0xff0000))&0xff0000;
g = ((c1&0xff00)-(c2&0xff00))&0xff00;
b = ((c1&0xff)-(c2&0xff))&0xff;
return r|g|b;
case 7:
return c1*c2;
case 8:
r = ((((c1&0xff0000)>>16) * ((c2&0xff0000)>> 16))&0xff) << 16;
g = ((((c1&0xff00)>>8) * ((c2&0xff00)>> 8))&0xff) << 8;
b = ((c1&0xff) * (c2&0xff))&0xff;
return r|g|b;
case 9:
if((c1&0xff0000)>(c2&0xff0000))
r=(c1&0xff0000);
else r=(c2&0xff0000);
if((c1&0xff00)>(c2&0xff00))
g=(c1&0xff00);
else g=(c2&0xff00);
if((c1&0xff)>(c2&0xff))
b=(c1&0xff);
else b=(c2&0xff);
return r|g|b;
case 10:
if((c1&0xff0000)<(c2&0xff0000))
r=(c1&0xff0000);
else r=(c2&0xff0000);
if((c1&0xff00)<(c2&0xff00))
g=(c1&0xff00);
else g=(c2&0xff00);
if((c1&0xff)<(c2&0xff))
b=(c1&0xff);
else b=(c2&0xff);
return r|g|b;
}
return 0;
}
/**
* Text description for combination
* @return string text description of offset
*/
public String getText()
{
switch(transNum)
{
case 0:
return "XOR";
case 1:
return "OR";
case 2:
return "AND";
case 3:
return "ADD";
case 4:
return "ADD (R,G,B separate)";
case 5:
return "SUB";
case 6:
return "SUB (R,G,B separate)";
case 7:
return "MUL";
case 8:
return "MUL (R,G,B separate)";
case 9:
return "Lightest (R, G, B separate)";
case 10:
return "Darkest (R, G, B separate)";
case 11:
return "Horizontal Interlace";
case 12:
return "Vertical Interlace";
}
return "???";
}
/**
* The combined image
* @return buffered image of the combined image
*/
public BufferedImage getImage()
{
return transform;
}
}

231
stegsolve/Combiner.java Normal file
View File

@@ -0,0 +1,231 @@
/*
* Combiner.java
*/
package stegsolve;
import javax.swing.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.filechooser.*;
import java.io.*;
import javax.imageio.*;
/**
* Image combiner
* @author Caesum
*/
public class Combiner extends JFrame
{
/**
* Label showing the current offset
*/
private JLabel nowShowing;
/**
* Panel for buttons
*/
private JPanel buttonPanel;
/**
* Increase offset button
*/
private JButton forwardButton;
/**
* Decrease offset button
*/
private JButton backwardButton;
/**
* Save image button
*/
private JButton saveButton;
/**
* Panel containing image
*/
private DPanel dp;
/**
* Scroll bars for image
*/
private JScrollPane scrollPane;
/**
* The images being combined
*/
private BufferedImage bi = null, bi2 = null;
/**
* The image after transformation
*/
private CombineTransform transform = null;
/**
* The current combination being tried
*/
private int inum=0;
/**
* current width/height
*/
private int w=0, h=0;
/**
* Creates new form Combiner
* @param b The image to solve
*/
public Combiner(BufferedImage b, BufferedImage b2)
{
bi = b;
bi2 = b2;
initComponents();
transform = new CombineTransform(bi, bi2);
newImage();
}
// <editor-fold defaultstate="collapsed" desc="Initcomponents()">
private void initComponents() {
nowShowing = new JLabel();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
this.add(nowShowing, BorderLayout.NORTH);
buttonPanel = new JPanel();
backwardButton = new JButton("<");
backwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
backwardButtonActionPerformed(evt);
}
});
forwardButton = new JButton(">");
forwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
forwardButtonActionPerformed(evt);
}
});
saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
saveButtonActionPerformed(evt);
}
});
buttonPanel.add(backwardButton);
buttonPanel.add(forwardButton);
buttonPanel.add(saveButton);
add(buttonPanel, BorderLayout.SOUTH);
backwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0), "back");
backwardButton.getActionMap().put("back", backButtonPress);
forwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0), "forward");
forwardButton.getActionMap().put("forward", forwardButtonPress);
dp = new DPanel();
scrollPane = new JScrollPane(dp);
add(scrollPane, BorderLayout.CENTER);
pack();
//setResizable(false);
}// </editor-fold>
/**
* This is used to map the left arrow key to the back button
*/
private Action backButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ backwardButtonActionPerformed(e);}
};
/**
* Move back by one offset
* @param evt Event
*/
private void backwardButtonActionPerformed(ActionEvent evt) {
if(transform == null) return;
transform.back();
updateImage();
}
/**
* This is used to map the right arrow key to the forward button
*/
private Action forwardButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ forwardButtonActionPerformed(e);}
};
/**
* Move forward by one offset
* @param evt Event
*/
private void forwardButtonActionPerformed(ActionEvent evt) {
if(bi == null) return;
transform.forward();
updateImage();
}
/**
* Save the current image
* @param evt Event
*/
private void saveButtonActionPerformed(ActionEvent evt)
{
File sfile = null;
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Images", "jpg", "gif", "png", "bmp");
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File("solved.bmp"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if(rVal == JFileChooser.APPROVE_OPTION)
{
sfile = fileChooser.getSelectedFile();
try
{
BufferedImage bbx = transform.getImage();
int rns = sfile.getName().lastIndexOf(".")+1;
if(rns==0)
ImageIO.write(bbx, "bmp", sfile);
else
ImageIO.write(bbx, sfile.getName().substring(rns), sfile);
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "写入文件失败: "+e.toString());
}
}
}
/**
* Update the text description and repaint the image
*/
private void updateImage()
{
if(transform.getImage().getWidth()!=w || transform.getImage().getHeight()!=h)
newImage();
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
repaint();
}
/**
* Show the image and make sure the form looks right
*/
private void newImage()
{
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
w = transform.getImage().getWidth();
h = transform.getImage().getHeight();
dp.setSize(transform.getImage().getWidth(),transform.getImage().getHeight());
dp.setPreferredSize(new Dimension(transform.getImage().getWidth(),transform.getImage().getHeight()));
this.setMaximumSize(getToolkit().getScreenSize());
pack();
dp.apply(100);
scrollPane.revalidate();
repaint();
this.setSize(500, 600);
}
}

205
stegsolve/DPanel.java Normal file
View File

@@ -0,0 +1,205 @@
/*
* DPanel.java
*/
package stegsolve;
import javax.swing.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.awt.image.*;
import java.awt.*;
import java.io.File;
import java.util.TooManyListenersException;
/**
* A JPanel with an image attached to it
* @author Caesum
*/
public class DPanel extends JPanel
{
private Dimension preferredSize = new Dimension(200, 200);
private Dimension defaultSize = new Dimension();
private Dimension currentSize = new Dimension();
private DropTarget dropTarget;
private DropTargetHandler dropTargetHandler;
private Point dragPoint;
private boolean dragOver = false;
public DPanel() {
//setBackground(Color.RED);
}
/**
* The image attached to this panel
*/
private BufferedImage bi = null;
/**
* Overridden paint method for the panel which
* paints the image on the panel
* @param g graphics object
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(bi!=null)
g.drawImage(bi, 0, 0, currentSize.width, currentSize.height, this);
}
/**
* Sets the image for the panel, and calls
* repaint
* @param bix Image to show on the panel
*/
public void setImage(BufferedImage bix)
{
bi = bix;
defaultSize.width = bi.getWidth();
defaultSize.height = bi.getHeight();
setSize(bi.getWidth(), bi.getHeight());
repaint();
//apply(100);
}
@Override
public Dimension getPreferredSize() {
return preferredSize;
}
public void apply(int percent) {
currentSize.width = (int)(defaultSize.width * (((float)percent)/100));
currentSize.height = (int)(defaultSize.height * (((float)percent)/100));
preferredSize = currentSize;
revalidate();
repaint();
}
protected class DropTargetHandler implements DropTargetListener {
protected void processDrag(DropTargetDragEvent dtde) {
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrag(DnDConstants.ACTION_COPY);
} else {
dtde.rejectDrag();
}
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {
processDrag(dtde);
SwingUtilities.invokeLater(new DragUpdate(true, dtde.getLocation()));
repaint();
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
processDrag(dtde);
SwingUtilities.invokeLater(new DragUpdate(true, dtde.getLocation()));
repaint();
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
@Override
public void dragExit(DropTargetEvent dte) {
SwingUtilities.invokeLater(new DragUpdate(false, null));
repaint();
}
@Override
public void drop(DropTargetDropEvent dtde) {
SwingUtilities.invokeLater(new DragUpdate(false, null));
Transferable transferable = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrop(dtde.getDropAction());
try {
java.util.List transferData = (java.util.List) transferable.getTransferData(DataFlavor.javaFileListFlavor);
if (transferData.size() == 1) {
StegSolve.that.loadImage((File)transferData.get(0));
dtde.dropComplete(true);
}
} catch (Exception ex) {
ex.printStackTrace();
}
} else {
dtde.rejectDrop();
}
}
}
protected DropTarget getMyDropTarget() {
if (dropTarget == null) {
dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, null);
}
return dropTarget;
}
protected DropTargetHandler getDropTargetHandler() {
if (dropTargetHandler == null) {
dropTargetHandler = new DropTargetHandler();
}
return dropTargetHandler;
}
@Override
public void addNotify() {
super.addNotify();
try {
getMyDropTarget().addDropTargetListener(getDropTargetHandler());
} catch (TooManyListenersException ex) {
ex.printStackTrace();
}
}
@Override
public void removeNotify() {
super.removeNotify();
getMyDropTarget().removeDropTargetListener(getDropTargetHandler());
}
/*
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (dragOver) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(0, 255, 0, 64));
g2d.fill(new Rectangle(getWidth(), getHeight()));
if (dragPoint != null && target != null) {
int x = dragPoint.x - 12;
int y = dragPoint.y - 12;
g2d.drawImage(target, x, y, this);
}
g2d.dispose();
}
}
*/
public class DragUpdate implements Runnable {
private boolean dragOver;
private Point dragPoint;
public DragUpdate(boolean dragOver, Point dragPoint) {
this.dragOver = dragOver;
this.dragPoint = dragPoint;
}
@Override
public void run() {
DPanel.this.dragOver = dragOver;
DPanel.this.dragPoint = dragPoint;
DPanel.this.repaint();
}
}
}

990
stegsolve/Extract.java Normal file
View File

@@ -0,0 +1,990 @@
/*
* Extract.java
*
* Created on 20-Apr-2011, 12:36:17
*/
package stegsolve;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
/**
* The data extraction form
* @author Caesum
*/
public class Extract extends javax.swing.JFrame {
/**
* The image data is being extracted from
*/
private BufferedImage bi = null;
/**
* The bytes being extracted
*/
private byte [] extract = null;
/**
* A mask of the bits selected for extraction
*/
private int mask = 0;
/**
* Number of bits selected for extraction
*/
private int maskbits = 0;
/**
* Boolean option - LSB first or MSB first?
*/
private boolean lsbFirst = false;
/**
* Boolean option - row by row or column by column?
*/
private boolean rowFirst = true;
/**
* Variable indicating the order of red, blue and green
* components to examine
*/
private int rgbOrder = 0;
/**
* Bit position in the current extract byte
*/
private int extractBitPos=0;
/**
* Byte position in the current extract
*/
private int extractBytePos=0;
/**
* Text that goes into the preview box
*/
private StringBuilder prev = null;
/**
* A JFileChooser object for choosing where to save the data
*/
private JFileChooser fileChooser;
/**
* Line separator for text files
*/
private String ls = System.getProperty("line.separator");
// TODO - inversion option
// TODO - optional offset to start
/**
* Creates new form Extract
*/
public Extract(BufferedImage b) {
bi = b;
initComponents();
}
/**
* Retrieves the mask from the bits selected on the form
*/
private void getMask()
{
mask = 0;
maskbits = 0;
if(ab7.isSelected()) { mask += 1<<31; maskbits++;}
if(ab6.isSelected()) { mask += 1<<30; maskbits++;}
if(ab5.isSelected()) { mask += 1<<29; maskbits++;}
if(ab4.isSelected()) { mask += 1<<28; maskbits++;}
if(ab3.isSelected()) { mask += 1<<27; maskbits++;}
if(ab2.isSelected()) { mask += 1<<26; maskbits++;}
if(ab1.isSelected()) { mask += 1<<25; maskbits++;}
if(ab0.isSelected()) { mask += 1<<24; maskbits++;}
if(rb7.isSelected()) { mask += 1<<23; maskbits++;}
if(rb6.isSelected()) { mask += 1<<22; maskbits++;}
if(rb5.isSelected()) { mask += 1<<21; maskbits++;}
if(rb4.isSelected()) { mask += 1<<20; maskbits++;}
if(rb3.isSelected()) { mask += 1<<19; maskbits++;}
if(rb2.isSelected()) { mask += 1<<18; maskbits++;}
if(rb1.isSelected()) { mask += 1<<17; maskbits++;}
if(rb0.isSelected()) { mask += 1<<16; maskbits++;}
if(gb7.isSelected()) { mask += 1<<15; maskbits++;}
if(gb6.isSelected()) { mask += 1<<14; maskbits++;}
if(gb5.isSelected()) { mask += 1<<13; maskbits++;}
if(gb4.isSelected()) { mask += 1<<12; maskbits++;}
if(gb3.isSelected()) { mask += 1<<11; maskbits++;}
if(gb2.isSelected()) { mask += 1<<10; maskbits++;}
if(gb1.isSelected()) { mask += 1<<9; maskbits++;}
if(gb0.isSelected()) { mask += 1<<8; maskbits++;}
if(bb7.isSelected()) { mask += 1<<7; maskbits++;}
if(bb6.isSelected()) { mask += 1<<6; maskbits++;}
if(bb5.isSelected()) { mask += 1<<5; maskbits++;}
if(bb4.isSelected()) { mask += 1<<4; maskbits++;}
if(bb3.isSelected()) { mask += 1<<3; maskbits++;}
if(bb2.isSelected()) { mask += 1<<2; maskbits++;}
if(bb1.isSelected()) { mask += 1<<1; maskbits++;}
if(bb0.isSelected()) { mask += 1; maskbits++;}
}
/**
* Retrieve the ordering options from the form
*/
private void getBitOrderOptions()
{
if(byRowButton.isSelected()) rowFirst = true;
else rowFirst = false;
if(LSBButton.isSelected()) lsbFirst = true;
else lsbFirst = false;
if(RGBButton.isSelected()) rgbOrder = 1;
else if (RBGButton.isSelected()) rgbOrder = 2;
else if (GRBButton.isSelected()) rgbOrder = 3;
else if (GBRButton.isSelected()) rgbOrder = 4;
else if (BRGButton.isSelected()) rgbOrder = 5;
else rgbOrder = 6;
}
/**
* Adds another bit to the extract
* @param num Non-zero if adding a 1-bit
*/
private void addBit(int num)
{
if(num!=0)
{
extract[extractBytePos]+=extractBitPos;
}
extractBitPos>>=1;
if(extractBitPos>=1)
return;
extractBitPos=128;
extractBytePos++;
if(extractBytePos<extract.length)
extract[extractBytePos]=0;
}
/**
* Examine 8 bits and check them against the mask to
* see if any should be extracted
* @param nextByte The byte to be examined
* @param bitMask The bitmask to be applied
*/
private void extract8Bits(int nextByte, int bitMask)
{
for(int i=0;i<8;i++)
{
if((mask&bitMask)!=0)
{
//System.out.println("call "+ mask+" "+bitMask+" "+nextByte);
addBit(nextByte & bitMask);
}
if(lsbFirst)
bitMask<<=1;
else
bitMask>>>=1;
}
}
/**
* Extract bits from the given byte taking account of
* the options selected
* @param nextByte the byte to extract bits from
*/
private void extractBits(int nextByte)
{
if(lsbFirst)
{
extract8Bits(nextByte,1<<24);
switch(rgbOrder)
{
case 1: //rgb
extract8Bits(nextByte,1<<16);
extract8Bits(nextByte,1<<8);
extract8Bits(nextByte,1);
break;
case 2: //rbg
extract8Bits(nextByte,1<<16);
extract8Bits(nextByte,1);
extract8Bits(nextByte,1<<8);
break;
case 3: //grb
extract8Bits(nextByte,1<<8);
extract8Bits(nextByte,1<<16);
extract8Bits(nextByte,1);
break;
case 4: //gbr
extract8Bits(nextByte,1<<8);
extract8Bits(nextByte,1);
extract8Bits(nextByte,1<<16);
break;
case 5: //brg
extract8Bits(nextByte,1);
extract8Bits(nextByte,1<<16);
extract8Bits(nextByte,1<<8);
break;
case 6: //bgr
extract8Bits(nextByte,1);
extract8Bits(nextByte,1<<8);
extract8Bits(nextByte,1<<16);
break;
}
}
else
{
extract8Bits(nextByte,1<<31);
switch(rgbOrder)
{
case 1: //rgb
extract8Bits(nextByte,1<<23);
extract8Bits(nextByte,1<<15);
extract8Bits(nextByte,1<<7);
break;
case 2: //rbg
extract8Bits(nextByte,1<<23);
extract8Bits(nextByte,1<<7);
extract8Bits(nextByte,1<<15);
break;
case 3: //grb
extract8Bits(nextByte,1<<15);
extract8Bits(nextByte,1<<23);
extract8Bits(nextByte,1<<7);
break;
case 4: //gbr
extract8Bits(nextByte,1<<15);
extract8Bits(nextByte,1<<7);
extract8Bits(nextByte,1<<23);
break;
case 5: //brg
extract8Bits(nextByte,1<<7);
extract8Bits(nextByte,1<<23);
extract8Bits(nextByte,1<<15);
break;
case 6: //bgr
extract8Bits(nextByte,1<<7);
extract8Bits(nextByte,1<<15);
extract8Bits(nextByte,1<<23);
break;
}
}
}
/**
* Generates the extract from the selected options
*/
private void generateExtract()
{
getMask();
getBitOrderOptions();
int len = bi.getHeight() * bi.getWidth();
len = len * maskbits; // number of bits to be extracted
len = (len +7)/8; // bytes to be extracted
extract = new byte[len];
extractBitPos = 128;
extractBytePos = 0;
//System.out.println(bi.getHeight()+" "+bi.getWidth()+" "+len+" "+mask);
if(rowFirst)
{
for(int j=0;j<bi.getHeight();j++)
for(int i=0;i<bi.getWidth();i++)
{
//System.out.println(i+" "+j+" "+extractBytePos);
extractBits(bi.getRGB(i, j));
}
}
else
{
for(int i=0;i<bi.getWidth();i++)
for(int j=0;j<bi.getHeight();j++)
extractBits(bi.getRGB(i, j));
}
}
/**
* Generates the preview from the selected options
* and given the extract has already been generated
*/
private void generatePreview()
{
boolean hexDump = hdInclude.isSelected();
prev = new StringBuilder();
for(int i=0;i<extract.length;i+=16)
{
if(hexDump)
{
for(int j=0;j<16&&i+j<extract.length;j++)
{
prev.append(m2(Integer.toHexString(((int)extract[i+j])&0xff)));
if(j==7)
prev.append(' ');
}
prev.append(" ");
}
for(int j=0;j<16&&i+j<extract.length;j++)
{
char c = (char)extract[i+j];
if(c>=32 && c<=128)
prev.append(c);
else
prev.append('.');
if(j==7) prev.append(' ');
}
prev.append(ls);
}
jPreview.setText(prev.toString());
}
/**
* Save the preview to a text file.
*/
private void savePreview() // to file
{
fileChooser = new JFileChooser(System.getProperty("user.dir"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
File sfile = null;
if(rVal == JFileChooser.APPROVE_OPTION)
{
sfile = fileChooser.getSelectedFile();
try
{
FileWriter fw = new FileWriter(sfile);
fw.write(jPreview.getText());
fw.close();
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "Failed to write file: "+e.toString());
}
}
}
/**
* Save the extract to a binary file
*/
private void saveExtract() // bin to file
{
fileChooser = new JFileChooser(System.getProperty("user.dir"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
File sfile = null;
if(rVal == JFileChooser.APPROVE_OPTION)
{
sfile = fileChooser.getSelectedFile();
try
{
FileOutputStream fw = new FileOutputStream(sfile);
fw.write(extract);
fw.close();
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "Failed to write file: "+e.toString());
}
}
}
/**
* Ensures a hex string is 2 bytes long, adding a leading zero if it is not
* @param hx hex string
* @return
*/
private String m2(String hx)
{
if(hx.length()<2)
return "0" + hx;
return hx;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
byGroup = new javax.swing.ButtonGroup();
bitGroup = new javax.swing.ButtonGroup();
planeGroup = new javax.swing.ButtonGroup();
optionsPanel = new javax.swing.JPanel();
lhSettingsPanel = new javax.swing.JPanel();
bitPlanesPanel = new javax.swing.JPanel();
alphaBitPanel = new javax.swing.JPanel();
alphaLabel = new javax.swing.JLabel();
aba = new javax.swing.JCheckBox();
ab7 = new javax.swing.JCheckBox();
ab6 = new javax.swing.JCheckBox();
ab5 = new javax.swing.JCheckBox();
ab4 = new javax.swing.JCheckBox();
ab3 = new javax.swing.JCheckBox();
ab2 = new javax.swing.JCheckBox();
ab1 = new javax.swing.JCheckBox();
ab0 = new javax.swing.JCheckBox();
redBitPanel = new javax.swing.JPanel();
redLabel = new javax.swing.JLabel();
rba = new javax.swing.JCheckBox();
rb7 = new javax.swing.JCheckBox();
rb6 = new javax.swing.JCheckBox();
rb5 = new javax.swing.JCheckBox();
rb4 = new javax.swing.JCheckBox();
rb3 = new javax.swing.JCheckBox();
rb2 = new javax.swing.JCheckBox();
rb1 = new javax.swing.JCheckBox();
rb0 = new javax.swing.JCheckBox();
greenBitPanel = new javax.swing.JPanel();
greenLabel = new javax.swing.JLabel();
gba = new javax.swing.JCheckBox();
gb7 = new javax.swing.JCheckBox();
gb6 = new javax.swing.JCheckBox();
gb5 = new javax.swing.JCheckBox();
gb4 = new javax.swing.JCheckBox();
gb3 = new javax.swing.JCheckBox();
gb2 = new javax.swing.JCheckBox();
gb1 = new javax.swing.JCheckBox();
gb0 = new javax.swing.JCheckBox();
blueBitPanel = new javax.swing.JPanel();
blueLabel = new javax.swing.JLabel();
bba = new javax.swing.JCheckBox();
bb7 = new javax.swing.JCheckBox();
bb6 = new javax.swing.JCheckBox();
bb5 = new javax.swing.JCheckBox();
bb4 = new javax.swing.JCheckBox();
bb3 = new javax.swing.JCheckBox();
bb2 = new javax.swing.JCheckBox();
bb1 = new javax.swing.JCheckBox();
bb0 = new javax.swing.JCheckBox();
prevSettingsPanel = new javax.swing.JPanel();
hdLabel = new javax.swing.JLabel();
hdInclude = new javax.swing.JCheckBox();
rhSettingsPanel = new javax.swing.JPanel();
orderSettingsPanel = new javax.swing.JPanel();
extractByPanel = new javax.swing.JPanel();
extractByLabel = new javax.swing.JLabel();
byRowButton = new javax.swing.JRadioButton();
byColumnButton = new javax.swing.JRadioButton();
bitOrderPanel = new javax.swing.JPanel();
bitOrderLabel = new javax.swing.JLabel();
MSBButton = new javax.swing.JRadioButton();
LSBButton = new javax.swing.JRadioButton();
bitPlaneOrderPanel = new javax.swing.JPanel();
bitPlaneOrderLabel = new javax.swing.JLabel();
RGBButton = new javax.swing.JRadioButton();
RBGButton = new javax.swing.JRadioButton();
GBRButton = new javax.swing.JRadioButton();
GRBButton = new javax.swing.JRadioButton();
BRGButton = new javax.swing.JRadioButton();
BGRButton = new javax.swing.JRadioButton();
exPreviewPanel = new javax.swing.JPanel();
exPreviewLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
jPreview = new javax.swing.JTextArea();
buttonsPanel = new javax.swing.JPanel();
previewButton = new javax.swing.JButton();
saveTextButton = new javax.swing.JButton();
saveBinButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(790, 560));
getContentPane().setLayout(new java.awt.BorderLayout(5, 5));
optionsPanel.setMinimumSize(new java.awt.Dimension(720, 280));
optionsPanel.setPreferredSize(new java.awt.Dimension(720, 280));
optionsPanel.setLayout(new java.awt.BorderLayout());
lhSettingsPanel.setMinimumSize(new java.awt.Dimension(360, 280));
lhSettingsPanel.setPreferredSize(new java.awt.Dimension(360, 280));
int bitPlanesWidth = 480;
bitPlanesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Bit Planes"));
bitPlanesPanel.setMinimumSize(new java.awt.Dimension(bitPlanesWidth, 200));
bitPlanesPanel.setPreferredSize(new java.awt.Dimension(bitPlanesWidth, 200));
alphaBitPanel.setName("alphaBitPanel"); // NOI18N
alphaBitPanel.setPreferredSize(new java.awt.Dimension(bitPlanesWidth-10, 34));
alphaLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
alphaLabel.setText("Alpha");
alphaLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
alphaLabel.setMaximumSize(new java.awt.Dimension(40, 14));
alphaLabel.setMinimumSize(new java.awt.Dimension(40, 14));
alphaLabel.setPreferredSize(new java.awt.Dimension(40, 14));
alphaBitPanel.add(alphaLabel);
aba.setText("all");
alphaBitPanel.add(aba);
checkAllListener(aba, ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0);
ab7.setText("7");
alphaBitPanel.add(ab7);
ab6.setText("6");
alphaBitPanel.add(ab6);
ab5.setText("5");
alphaBitPanel.add(ab5);
ab4.setText("4");
alphaBitPanel.add(ab4);
ab3.setText("3");
alphaBitPanel.add(ab3);
ab2.setText("2");
alphaBitPanel.add(ab2);
ab1.setText("1");
alphaBitPanel.add(ab1);
ab0.setText("0");
alphaBitPanel.add(ab0);
bitPlanesPanel.add(alphaBitPanel);
alphaBitPanel.getAccessibleContext().setAccessibleName("alphaBitPanel");
redBitPanel.setPreferredSize(new java.awt.Dimension(bitPlanesWidth-10, 34));
redLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
redLabel.setText("Red");
redLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
redLabel.setMaximumSize(new java.awt.Dimension(40, 14));
redLabel.setMinimumSize(new java.awt.Dimension(40, 14));
redLabel.setPreferredSize(new java.awt.Dimension(40, 14));
redBitPanel.add(redLabel);
rba.setText("all");
redBitPanel.add(rba);
checkAllListener(rba, rb7, rb6, rb5, rb4, rb3, rb2, rb1, rb0);
rb7.setText("7");
redBitPanel.add(rb7);
rb6.setText("6");
redBitPanel.add(rb6);
rb5.setText("5");
redBitPanel.add(rb5);
rb4.setText("4");
redBitPanel.add(rb4);
rb3.setText("3");
redBitPanel.add(rb3);
rb2.setText("2");
redBitPanel.add(rb2);
rb1.setText("1");
redBitPanel.add(rb1);
rb0.setText("0");
redBitPanel.add(rb0);
bitPlanesPanel.add(redBitPanel);
greenBitPanel.setPreferredSize(new java.awt.Dimension(bitPlanesWidth-10, 34));
greenLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
greenLabel.setText("Green");
greenLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
greenLabel.setMaximumSize(new java.awt.Dimension(40, 14));
greenLabel.setMinimumSize(new java.awt.Dimension(40, 14));
greenLabel.setPreferredSize(new java.awt.Dimension(40, 14));
greenBitPanel.add(greenLabel);
gba.setText("all");
greenBitPanel.add(gba);
checkAllListener(gba, gb7, gb6, gb5, gb4, gb3, gb2, gb1, gb0);
gb7.setText("7");
greenBitPanel.add(gb7);
gb6.setText("6");
greenBitPanel.add(gb6);
gb5.setText("5");
greenBitPanel.add(gb5);
gb4.setText("4");
greenBitPanel.add(gb4);
gb3.setText("3");
greenBitPanel.add(gb3);
gb2.setText("2");
greenBitPanel.add(gb2);
gb1.setText("1");
greenBitPanel.add(gb1);
gb0.setText("0");
greenBitPanel.add(gb0);
bitPlanesPanel.add(greenBitPanel);
blueBitPanel.setPreferredSize(new java.awt.Dimension(bitPlanesWidth-10, 34));
blueLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
blueLabel.setText("Blue");
blueLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
blueLabel.setMaximumSize(new java.awt.Dimension(40, 14));
blueLabel.setMinimumSize(new java.awt.Dimension(40, 14));
blueLabel.setPreferredSize(new java.awt.Dimension(40, 14));
blueBitPanel.add(blueLabel);
bba.setText("all");
blueBitPanel.add(bba);
checkAllListener(bba, bb7, bb6, bb5, bb4, bb3, bb2, bb1, bb0);
bb7.setText("7");
blueBitPanel.add(bb7);
bb6.setText("6");
blueBitPanel.add(bb6);
bb5.setText("5");
blueBitPanel.add(bb5);
bb4.setText("4");
blueBitPanel.add(bb4);
bb3.setText("3");
blueBitPanel.add(bb3);
bb2.setText("2");
blueBitPanel.add(bb2);
bb1.setText("1");
blueBitPanel.add(bb1);
bb0.setText("0");
blueBitPanel.add(bb0);
bitPlanesPanel.add(blueBitPanel);
lhSettingsPanel.add(bitPlanesPanel);
prevSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Preview Settings"));
prevSettingsPanel.setMinimumSize(new java.awt.Dimension(360, 50));
prevSettingsPanel.setPreferredSize(new java.awt.Dimension(360, 50));
prevSettingsPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 5, 0));
hdLabel.setText("Include Hex Dump In Preview");
prevSettingsPanel.add(hdLabel);
hdInclude.setSelected(true);
prevSettingsPanel.add(hdInclude);
lhSettingsPanel.add(prevSettingsPanel);
optionsPanel.add(lhSettingsPanel, java.awt.BorderLayout.CENTER);
rhSettingsPanel.setMinimumSize(new java.awt.Dimension(300, 280));
rhSettingsPanel.setPreferredSize(new java.awt.Dimension(300, 280));
rhSettingsPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 0, 5));
orderSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Order settings"));
orderSettingsPanel.setPreferredSize(new java.awt.Dimension(280, 260));
orderSettingsPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
extractByLabel.setText("Extract By");
extractByPanel.add(extractByLabel);
byGroup.add(byRowButton);
byRowButton.setSelected(true);
byRowButton.setText("Row");
extractByPanel.add(byRowButton);
byGroup.add(byColumnButton);
byColumnButton.setText("Column");
extractByPanel.add(byColumnButton);
orderSettingsPanel.add(extractByPanel);
bitOrderPanel.setPreferredSize(new java.awt.Dimension(250, 41));
bitOrderPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
bitOrderLabel.setText("Bit Order");
bitOrderPanel.add(bitOrderLabel);
bitGroup.add(MSBButton);
MSBButton.setSelected(true);
MSBButton.setText("MSB First");
bitOrderPanel.add(MSBButton);
bitGroup.add(LSBButton);
LSBButton.setText("LSB First");
bitOrderPanel.add(LSBButton);
orderSettingsPanel.add(bitOrderPanel);
bitPlaneOrderPanel.setPreferredSize(new java.awt.Dimension(250, 130));
bitPlaneOrderLabel.setText("Bit Plane Order");
planeGroup.add(RGBButton);
RGBButton.setSelected(true);
RGBButton.setText("RGB");
planeGroup.add(RBGButton);
RBGButton.setText("RBG");
planeGroup.add(GBRButton);
GBRButton.setText("GBR");
planeGroup.add(GRBButton);
GRBButton.setText("GRB");
planeGroup.add(BRGButton);
BRGButton.setText("BRG");
planeGroup.add(BGRButton);
BGRButton.setText("BGR");
javax.swing.GroupLayout bitPlaneOrderPanelLayout = new javax.swing.GroupLayout(bitPlaneOrderPanel);
bitPlaneOrderPanel.setLayout(bitPlaneOrderPanelLayout);
bitPlaneOrderPanelLayout.setHorizontalGroup(
bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bitPlaneOrderLabel)
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addComponent(RBGButton)
.addGap(18, 18, 18)
.addComponent(BRGButton))
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addComponent(RGBButton)
.addGap(18, 18, 18)
.addComponent(GRBButton))
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addComponent(GBRButton)
.addGap(18, 18, 18)
.addComponent(BGRButton)))))
.addContainerGap(72, Short.MAX_VALUE))
);
bitPlaneOrderPanelLayout.setVerticalGroup(
bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(bitPlaneOrderPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(bitPlaneOrderLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(RGBButton)
.addComponent(GRBButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(RBGButton)
.addComponent(BRGButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(bitPlaneOrderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(GBRButton)
.addComponent(BGRButton))
.addContainerGap(13, Short.MAX_VALUE))
);
orderSettingsPanel.add(bitPlaneOrderPanel);
rhSettingsPanel.add(orderSettingsPanel);
optionsPanel.add(rhSettingsPanel, java.awt.BorderLayout.EAST);
getContentPane().add(optionsPanel, java.awt.BorderLayout.CENTER);
optionsPanel.getAccessibleContext().setAccessibleName("saveText");
exPreviewPanel.setLayout(new java.awt.BorderLayout());
exPreviewLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
exPreviewLabel.setText("Extract Preview");
exPreviewLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
exPreviewLabel.setMinimumSize(new java.awt.Dimension(20, 14));
exPreviewPanel.add(exPreviewLabel, java.awt.BorderLayout.CENTER);
exPreviewLabel.getAccessibleContext().setAccessibleName("previewLabel");
jPreview.setColumns(20);
jPreview.setEditable(false);
jPreview.setFont(new java.awt.Font("Courier New", 0, 14));
jPreview.setRows(10);
jPreview.setMargin(new java.awt.Insets(5, 5, 5, 5));
jScrollPane1.setViewportView(jPreview);
exPreviewPanel.add(jScrollPane1, java.awt.BorderLayout.PAGE_END);
getContentPane().add(exPreviewPanel, java.awt.BorderLayout.NORTH);
previewButton.setText("Preview");
previewButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
previewButtonActionPerformed(evt);
}
});
buttonsPanel.add(previewButton);
previewButton.getAccessibleContext().setAccessibleName("previewButton");
saveTextButton.setText("Save Text");
saveTextButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveTextButtonActionPerformed(evt);
}
});
buttonsPanel.add(saveTextButton);
saveTextButton.getAccessibleContext().setAccessibleName("saveTextButton");
saveBinButton.setText("Save Bin");
saveBinButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveBinButtonActionPerformed(evt);
}
});
buttonsPanel.add(saveBinButton);
saveBinButton.getAccessibleContext().setAccessibleName("saveBinButton");
cancelButton.setText("Cancel");
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
buttonsPanel.add(cancelButton);
cancelButton.getAccessibleContext().setAccessibleName("cancelButton");
getContentPane().add(buttonsPanel, java.awt.BorderLayout.SOUTH);
pack();
}// </editor-fold>//GEN-END:initComponents
private void checkAllListener(JCheckBox ca, JCheckBox c7, JCheckBox c6, JCheckBox c5, JCheckBox c4, JCheckBox c3, JCheckBox c2, JCheckBox c1, JCheckBox c0) {
ca.addItemListener(e -> {
c7.setSelected(ca.isSelected());
c6.setSelected(ca.isSelected());
c5.setSelected(ca.isSelected());
c4.setSelected(ca.isSelected());
c3.setSelected(ca.isSelected());
c2.setSelected(ca.isSelected());
c1.setSelected(ca.isSelected());
c0.setSelected(ca.isSelected());
});
}
/**
* Generate the extract and generate the preview
* @param evt Event
*/
private void previewButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previewButtonActionPerformed
generateExtract();
generatePreview();
}//GEN-LAST:event_previewButtonActionPerformed
/**
* Generate the extract and the preview, and save it as text
* @param evt Event
*/
private void saveTextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTextButtonActionPerformed
generateExtract();
generatePreview();
savePreview();
}//GEN-LAST:event_saveTextButtonActionPerformed
/**
* Generate the extract and save it as binary
* @param evt Event
*/
private void saveBinButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveBinButtonActionPerformed
generateExtract();
saveExtract();
}//GEN-LAST:event_saveBinButtonActionPerformed
/**
* Close the form
* @param evt Event
*/
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton BGRButton;
private javax.swing.JRadioButton BRGButton;
private javax.swing.JRadioButton GBRButton;
private javax.swing.JRadioButton GRBButton;
private javax.swing.JRadioButton LSBButton;
private javax.swing.JRadioButton MSBButton;
private javax.swing.JRadioButton RBGButton;
private javax.swing.JRadioButton RGBButton;
private javax.swing.JCheckBox ab0;
private javax.swing.JCheckBox ab1;
private javax.swing.JCheckBox ab2;
private javax.swing.JCheckBox ab3;
private javax.swing.JCheckBox ab4;
private javax.swing.JCheckBox ab5;
private javax.swing.JCheckBox ab6;
private javax.swing.JCheckBox ab7;
private javax.swing.JCheckBox aba;
private javax.swing.JPanel alphaBitPanel;
private javax.swing.JLabel alphaLabel;
private javax.swing.JCheckBox bb0;
private javax.swing.JCheckBox bb1;
private javax.swing.JCheckBox bb2;
private javax.swing.JCheckBox bb3;
private javax.swing.JCheckBox bb4;
private javax.swing.JCheckBox bb5;
private javax.swing.JCheckBox bb6;
private javax.swing.JCheckBox bb7;
private javax.swing.JCheckBox bba;
private javax.swing.ButtonGroup bitGroup;
private javax.swing.JLabel bitOrderLabel;
private javax.swing.JPanel bitOrderPanel;
private javax.swing.JLabel bitPlaneOrderLabel;
private javax.swing.JPanel bitPlaneOrderPanel;
private javax.swing.JPanel bitPlanesPanel;
private javax.swing.JPanel blueBitPanel;
private javax.swing.JLabel blueLabel;
private javax.swing.JPanel buttonsPanel;
private javax.swing.JRadioButton byColumnButton;
private javax.swing.ButtonGroup byGroup;
private javax.swing.JRadioButton byRowButton;
private javax.swing.JButton cancelButton;
private javax.swing.JLabel exPreviewLabel;
private javax.swing.JPanel exPreviewPanel;
private javax.swing.JLabel extractByLabel;
private javax.swing.JPanel extractByPanel;
private javax.swing.JCheckBox gb0;
private javax.swing.JCheckBox gb1;
private javax.swing.JCheckBox gb2;
private javax.swing.JCheckBox gb3;
private javax.swing.JCheckBox gb4;
private javax.swing.JCheckBox gb5;
private javax.swing.JCheckBox gb6;
private javax.swing.JCheckBox gb7;
private javax.swing.JCheckBox gba;
private javax.swing.JPanel greenBitPanel;
private javax.swing.JLabel greenLabel;
private javax.swing.JCheckBox hdInclude;
private javax.swing.JLabel hdLabel;
private javax.swing.JTextArea jPreview;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JPanel lhSettingsPanel;
private javax.swing.JPanel optionsPanel;
private javax.swing.JPanel orderSettingsPanel;
private javax.swing.ButtonGroup planeGroup;
private javax.swing.JPanel prevSettingsPanel;
private javax.swing.JButton previewButton;
private javax.swing.JCheckBox rb0;
private javax.swing.JCheckBox rb1;
private javax.swing.JCheckBox rb2;
private javax.swing.JCheckBox rb3;
private javax.swing.JCheckBox rb4;
private javax.swing.JCheckBox rb5;
private javax.swing.JCheckBox rb6;
private javax.swing.JCheckBox rb7;
private javax.swing.JCheckBox rba;
private javax.swing.JPanel redBitPanel;
private javax.swing.JLabel redLabel;
private javax.swing.JPanel rhSettingsPanel;
private javax.swing.JButton saveBinButton;
private javax.swing.JButton saveTextButton;
// End of variables declaration//GEN-END:variables
}

994
stegsolve/FileAnalysis.java Normal file
View File

@@ -0,0 +1,994 @@
/*
* FileAnalysis.java
*
* Created on 27-Apr-2011, 11:14:48
*/
package stegsolve;
import java.io.*;
import java.util.zip.CRC32;
/**
* File Analysis by examining the file format
* @author Caesum
*/
public class FileAnalysis extends javax.swing.JFrame {
/**
* String containing the file analysis report
*/
private StringBuilder rep;
/**
* The file in bytes
*/
private byte [] f = null;
/** Creates new form FileAnalysis */
public FileAnalysis(File ifile) {
initComponents();
analyse_file(ifile);
}
/**
* Reads the data from the file and compiles
* the analysis report
* @param ifile File to analyse
*/
private void analyse_file(File ifile)
{
rep = new StringBuilder();
rep.append("<html><center><b>");
rep.append("文件格式报告");
rep.append("</b></center>");
rep.append(("<br>文件: "+ifile.getName()));
try{
FileInputStream fis = new FileInputStream(ifile);
f = new byte[(int)ifile.length()];
fis.read(f);
rep.append(("<br>Read "+Integer.toHexString(f.length)+" bytes"));
analyse();
}
catch(Exception e)
{
rep.append(("读取文件时出错: "+e.toString()));
}
rep.append("</html>");
report.setText(rep.toString());
}
/**
* Checks the header and chooses the correct subtype
* for analysis
*/
private void analyse()
{
// analyse f, write report to rep
if(f.length<4)
{
rep.append("<br>文件太短?");
return;
}
if(f[0] == 'B' && f[1] == 'M')
analyse_bmp();
else if(f[0]==(byte)137 && f[1]==(byte)80 && f[2]==78 && f[3]==71)
analyse_png();
else if(f.length>=6 && f[0]=='G' && f[1]=='I' && f[2]=='F' && f[3]=='8' && (f[4]=='7' ||
f[4]=='9') && f[5]=='a')
analyse_gif();
else if(f[0]==(byte)0xff && f[1]==(byte)0xd8)
analyse_jpg();
else rep.append("<br>文件格式分析代码尚未完成!");
}
/**
* Analysis particular to a jpeg/jpg image
*/
private void analyse_jpg()
{
int cpos = 0;
cpos = analyse_jpg_sections(cpos);
if(cpos<f.length)
{
rep.append(("<br>文件末尾的附加字节数 = " +(f.length-cpos)));
rep.append("<br>转储附加字节:");
fdump(cpos, f.length);
}
}
/**
* Analyses one particular jpeg section
* @param pos Position in the file
* @return End position in the file
*/
private int analyse_jpg_sections(int pos)
{
if(f[pos]==(byte)0xff && f[pos+1]==(byte)0xd8)
{
rep.append("<br>图像的开头");
pos+=2;
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xd9)
{
rep.append("<br><br>图像结尾");
pos+=2;
return pos;
}
else if(f[pos] == (byte) 0xff &&
( (f[pos + 1] >= (byte) 0xc0 && f[pos + 1] <= (byte) 0xc3)
|| (f[pos + 1] >= (byte) 0xc5 && f[pos + 1] <= (byte) 0xc7)
|| (f[pos + 1] >= (byte) 0xc9 && f[pos + 1] <= (byte) 0xcb)
|| (f[pos + 1] >= (byte) 0xcd && f[pos + 1] <= (byte) 0xcf)
|| f[pos+1]==(byte)0xde))
{
if(f[pos+1]==(byte)0xc0)
rep.append("<br><br>Start of frame : Baseline DCT");
else if(f[pos + 1] == (byte) 0xc1)
rep.append("<br><br>Start of frame : Extended sequential DCT");
else if(f[pos + 1] == (byte) 0xc2)
rep.append("<br><br>Start of frame : Progressive DCT");
else if(f[pos + 1] == (byte) 0xc3)
rep.append("<br><br>Start of frame : Lossless (sequential)");
else if(f[pos + 1] == (byte) 0xc5)
rep.append("<br><br>Start of frame : Differential sequential DCT");
else if(f[pos + 1] == (byte) 0xc6)
rep.append("<br><br>Start of frame : Differential progressive DCT");
else if(f[pos + 1] == (byte) 0xc7)
rep.append("<br><br>Start of frame : Differential lossless (sequential)");
else if(f[pos + 1] == (byte) 0xc9)
rep.append("<br><br>Start of frame : Extended sequential DCT");
else if(f[pos + 1] == (byte) 0xca)
rep.append("<br><br>Start of frame : Progressive DCT");
else if(f[pos + 1] == (byte) 0xcb)
rep.append("<br><br>Start of frame : Lossless (sequential)");
else if(f[pos + 1] == (byte) 0xcd)
rep.append("<br><br>Start of frame : Differential sequential DCT");
else if(f[pos + 1] == (byte) 0xce)
rep.append("<br><br>Start of frame : Differential progressive DCT");
else if(f[pos + 1] == (byte) 0xcf)
rep.append("<br><br>Start of frame : Differential lossless (sequential)");
else if(f[pos + 1] == (byte) 0xde)
rep.append("<br><br>Start of frame : DHP");
if(f[pos+1]<(byte)0xc8)
rep.append(" (Huffman coding)");
else rep.append(" (arithmetic coding)");
rep.append(("<br>Header Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append(("<br>Precision: " + Integer.toHexString(uf(pos+4))));
rep.append(("<br>Image lines: " + Integer.toHexString(png_get_word(pos+5)) + " (" + png_get_word(pos+5) + ")"));
rep.append(("<br>Samples per line: " + Integer.toHexString(png_get_word(pos+7)) + " (" + png_get_word(pos+7) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xc4)
{
rep.append("<br><br>Huffman table");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xcc)
{
rep.append("<br><br>Arithmetic coding conditioning");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] >= (byte) 0xd0 && f[pos + 1] <= (byte) 0xd7)
{
rep.append("<br><br>Restart interval");
pos+=2;
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xda)
{
rep.append("<br><br>Start of scan");
rep.append(("<br>Header Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
pos+=2+png_get_word(pos+2);
int ct=pos;
while(f[ct]!=(byte)0xff || (f[ct]==(byte)0xff && f[ct+1]==0)
|| (f[ct]==(byte)0xff && f[ct+1]>=(byte)0xd0&&f[ct+1]<=(byte)0xd7))
ct++;
rep.append(("<br>Detected " + (ct-pos) + " bytes in scan"));
pos=ct;
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xdb)
{
rep.append("<br><br>Quantisation table");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xdc)
{
rep.append("<br><br>Define number of lines");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append(" (Should be 4)");
rep.append(("<br>Number: " + Integer.toHexString(png_get_word(pos+4)) + " (" + png_get_word(pos+4) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xdd)
{
rep.append("<br><br>Define Restart interval");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append(" (Should be 4)");
rep.append(("<br>Interval: " + Integer.toHexString(png_get_word(pos+4)) + " (" + png_get_word(pos+4) + ")"));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xdf)
{
rep.append("<br><br>Expand reference components");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append(" (Should be 3)");
rep.append(("<br>Value: " + Integer.toHexString(uf(pos+4))));
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] >= (byte) 0xe0 &&f[pos + 1] <= (byte) 0xef)
{
rep.append("<br><br>Application data");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append("<br>Dump of data:");
fdump(pos+2,pos+2+png_get_word(pos+2)-1);
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xfe)
{
rep.append("<br><br>Comment data");
rep.append(("<br>Length: " + Integer.toHexString(png_get_word(pos+2)) + " (" + png_get_word(pos+2) + ")"));
rep.append("<br>Dump of data:");
fdump(pos+2,pos+2+png_get_word(pos+2)-1);
pos+=2+png_get_word(pos+2);
}
else if(f[pos] == (byte) 0xff && f[pos + 1] == (byte) 0xff)
{
pos++;
}
else return pos;
return analyse_jpg_sections(pos);
}
/**
* Analysis particular to a gif image
*/
private void analyse_gif()
{
if(f.length<13)
{
rep.append("<br>file too short?");
return;
}
rep.append(("<br>Width: " + get_hword(6) + " (" + get_word(6) + ")"));
rep.append(("<br>Height: " + get_hword(8) + " (" + get_word(8) + ")"));
rep.append(("<br>Flags: " + Integer.toHexString(uf(10))));
int flags = uf(10);
int gctsize=0;
if((flags&0x80)>0)
{
rep.append(" (Global Colour Table)");
if((flags&0x10)>0) rep.append(" (Sorted GCT)");
gctsize = 1<<(((flags&0x07)+1));
rep.append((" (GCT Size = " + gctsize + ")"));
}
rep.append((" (Color Resolution = " + (((flags>>3)&0x03)+1) + ")"));
rep.append(("<br>Background color index: " + uf(11)));
rep.append(("<br>Pixel aspect ratio: " + uf(12)));
int cpos = 13;
if(f.length<cpos+gctsize*3)
{
rep.append("<br>file too short?");
return;
}
if(gctsize>0)
{
rep.append("<br><br>Global Colour Table:");
for(int i=0;i<gctsize;i++)
{
rep.append("<br>");
for(int j=0;j<3;j++)
{
rep.append(m2(Integer.toHexString(uf(cpos + i * 3 + j))));
rep.append(" ");
}
rep.append(" ");
for(int j=0;j<3;j++)
{
char c=(char)uf(cpos + i * 3 + j);
if(c<32||c>0x7f)c='.';
rep.append((""+c));
}
}
cpos+=gctsize*3;
}
cpos = check_gif_blocks(cpos);
if(cpos<f.length)
{
rep.append(("<br>Additional bytes at end of file = " +(f.length-cpos)));
rep.append("<br>Dump of additional bytes:");
fdump(cpos, f.length);
}
}
/**
* Analysis of a gif block
* @param pos Position in the file
* @return Position after this block
*/
private int check_gif_blocks(int pos)
{
if(f[pos]==0x2c)
{
if(pos+10>=f.length) return pos;
rep.append("<br><br>Image Descriptor");
rep.append(("<br>Left: " + get_hword(pos+1) + " (" + get_word(pos+1) + ")"));
rep.append(("<br>Top: " + get_hword(pos+3) + " (" + get_word(pos+3) + ")"));
rep.append(("<br>Width: " + get_hword(pos+5) + " (" + get_word(pos+5) + ")"));
rep.append(("<br>Height: " + get_hword(pos+7) + " (" + get_word(pos+7) + ")"));
rep.append(("<br>Flags: " + Integer.toHexString(uf(pos+9))));
int flags = uf(pos+9);
int lctsize = 0;
if((flags&128)>0)
{
rep.append(" (Local colour table)");
lctsize=1<<((flags&0x07)+1);
rep.append((" (LCT Size = " + lctsize + ""));
}
if((flags&64)>0) rep.append(" (Interlace)");
if((flags&32)>0) rep.append(" (Sort)");
if((flags&24)>0) rep.append(" (**Reserved flags set **)");
pos=pos+10;
if(f.length<pos+lctsize*3)
{
rep.append("<br>file too short?");
return pos;
}
if(lctsize>0)
{
rep.append("<br><br>Local Colour Table:");
for(int i=0;i<lctsize;i++)
{
rep.append("<br>");
for(int j=0;j<3;j++)
{
rep.append(m2(Integer.toHexString(uf(pos + i * 3 + j))));
rep.append(" ");
}
rep.append(" ");
for(int j=0;j<3;j++)
{
char c=(char)uf(pos + i * 3 + j);
if(c<32||c>0x7f)c='.';
rep.append((""+c));
}
}
pos+=lctsize*3;
}
rep.append(("<br>LZW size = " + uf(pos)));
pos++;
while(uf(pos)>0) pos+=uf(pos)+1;
pos++;
}
else if(f[pos]==0x21 && uf(pos+1)==0xf9)
{
if(pos+8>=f.length) return pos;
rep.append("<br><br>Graphic control extension");
rep.append(("<br>Size : " + uf(pos+2) + " (must be 4)"));
rep.append(("<br>Flags: " + Integer.toHexString(uf(pos+3))));
int flags = uf(pos+3);
if((flags&224)>0) rep.append(" (**Reserved flags set **)");
if((flags&1)>0) rep.append(" (Transparency flag)");
rep.append(("<br>Delay time: " + get_word(pos+4)));
rep.append(("<br>Transparent color index: " + uf(6)));
rep.append(("<br>Terminator: " + Integer.toHexString(uf(pos+7))));
pos=pos+8;
}
else if(f[pos]==0x21 && uf(pos+1)==0xfe)
{
if(pos+3>=f.length) return pos;
rep.append("<br><br>Comment extension");
rep.append("<br>Dump of data:");
pos+=2;
while(uf(pos)>0)
{
fdump(pos+1,pos+uf(pos));
pos += uf(pos) + 1;
}
pos++;
}
else if(f[pos]==0x21 && uf(pos+1)==0x01)
{
if(pos+16>=f.length) return pos;
rep.append("<br><br>Plain Text extension");
rep.append(("<br>Size : " + uf(pos+2) + " (must be 12)"));
rep.append(("<br>Left: " + get_hword(pos+3) + " (" + get_word(pos+3) + ")"));
rep.append(("<br>Top: " + get_hword(pos+5) + " (" + get_word(pos+5) + ")"));
rep.append(("<br>Width: " + get_hword(pos+7) + " (" + get_word(pos+7) + ")"));
rep.append(("<br>Height: " + get_hword(pos+9) + " (" + get_word(pos+9) + ")"));
rep.append(("<br>Cell Width : " + uf(pos+11)));
rep.append(("<br>Cell Height : " + uf(pos+12)));
rep.append(("<br>Foreground Color Index : " + uf(pos+13)));
rep.append(("<br>Background Color Index : " + uf(pos+14)));
rep.append("<br>Dump of data:");
pos+=15;
while(uf(pos)>0)
{
fdump(pos+1,pos+uf(pos));
pos += uf(pos) + 1;
}
pos++;
}
else if(f[pos]==0x21 && uf(pos+1)==0xff)
{
if(pos+14>=f.length) return pos;
rep.append("<br><br>Application extension");
rep.append(("<br>Size : " + uf(pos+2) + " (must be 11)"));
rep.append("<br>Identifier:");
fdump(pos+3,pos+10);
rep.append("<br>Authentication code:");
fdump(pos+11,pos+13);
rep.append("<br>Application data:");
pos+=14;
while(uf(pos)>0)
{
fdump(pos+1,pos+uf(pos));
pos += uf(pos) + 1;
}
pos++;
}
else if(f[pos]==0x3b)
{
rep.append("<br><br>Trailer block");
return pos+1;
}
else return pos;
return check_gif_blocks(pos);
}
/**
* Analysis particular to a png file
*/
private void analyse_png()
{
if(f.length<8)
{
rep.append("<br>file too short?");
return;
}
if(f[4]!=13||f[5]!=10||f[6]!=26||f[7]!=10)
{
rep.append("<br>Error in header, bytes 5-8 should be 0d 0a 1a 0a");
}
int cpos = check_png_chunks(8);
if(cpos<f.length)
{
rep.append(("<br>Additional bytes at end of file = " +(f.length-cpos)));
rep.append("<br>Dump of additional bytes:");
fdump(cpos, f.length);
}
}
/**
* Analyse png chunks
* @param start Position in the file
* @return Position after the chunks
*/
private int check_png_chunks(int start)
{
if(start+12>f.length)
{
rep.append("<br>Premature end to file?");
return start;
}
int length = png_get_dword(start);
rep.append("<br><br>Chunk: ");
if((f[4]&64)>0)
{
rep.append("<br>Ancillary - provides additional information");
}
else
{
rep.append("<br>Critical - necessary for display of image MUST BE recognized to proceed");
}
if((f[5]&64)>0)
{
rep.append("<br>Private, investigate this!!");
}
else
{
rep.append("<br>Public");
}
if((f[6]&64)>0)
{
rep.append("<br>Chunk has a reserved flag set, **investigate this**!");
}
if((f[7]&64)>0)
{
rep.append("<br>Safe to copy, chunk may propagate to other files");
}
else
{
rep.append("<br>Unsafe to copy unless known to software");
}
fdump(start+4,start+7);
rep.append(("<br>Data length = "+length + " bytes"));
rep.append(("<br>CRC = "+png_get_hdword(start+8+length)));
CRC32 cc = new CRC32();
cc.reset();
cc.update(f,start+4,4+length);
if((int)cc.getValue()!=png_get_dword(start+8+length))
{
rep.append("<br>Calculated CRC = " + Integer.toHexString((int)cc.getValue()));
}
if(start+12+length>f.length)
{
rep.append("<br>Not enough room in file for data?");
return start;
}
int typ = png_get_dword(start+4);
if(typ==0x49454E44) // IEND
return start + 12;
else if(typ == 0x49484452) // IHDR
{
rep.append(("<br>Width: " + png_get_hdword(start+8) + " ("+png_get_dword(start+8)+")"));
rep.append(("<br>Height: " + png_get_hdword(start+12) + " ("+png_get_dword(start+12)+")"));
rep.append(("<br>Bit Depth: " + f[start+16]));
rep.append(("<br>Color Type: " + f[start+17]));
if(f[start+17]==0) rep.append(" (Grayscale)");
if(f[start+17]==2) rep.append(" (RGB Triples)");
if(f[start+17]==3) rep.append(" (Palette Indexed)");
if(f[start+17]==4) rep.append(" (Grayscale + Alpha)");
if(f[start+17]==6) rep.append(" (RGB + Alpha)");
rep.append(("<br>Compression Method: " + f[start+18]));
if(f[start+18]==0) rep.append(" (deflate)");
else rep.append(" (unknown)");
rep.append(("<br>Filter Method: " + f[start+19]));
if(f[start+19]==0) rep.append(" (adaptive)");
else rep.append(" (unknown)");
rep.append(("<br>Interlace Method: " + f[start+20]));
if(f[start+20]==0) rep.append(" (none)");
else if(f[start + 20] == 1) rep.append(" (adam7)");
else rep.append(" (unknown)");
}
else if(typ == 0x504C5445) //PLTE
{
rep.append(("<br>Palette contains " + (length/3) +
" RGB entries, NB if colortype is 2 or 6 this could be hiding something."));
rep.append("<br>Dump of palette:");
for(int i=0;i<length/3;i++)
{
rep.append("<br>");
for(int j=0;j<4;j++)
{
rep.append(m2(Integer.toHexString(uf(start+8 + i * 3 + j))));
rep.append(" ");
}
rep.append(" ");
for(int j=0;j<3;j++)
{
char c=(char)uf(start+8 + i * 3 + j);
if(c<32||c>0x7f)c='.';
rep.append((""+c));
}
}
}
else if(typ == 0x49444154) //IDAT
{
rep.append("<br>Image data, compressed");
}
else if(typ == 0x624B4744) //bKGD
{
rep.append("<br>Background data, optional");
rep.append("<br>NB: should be after PLTE chunk and before first IDAT");
if(length!=1&&length!=2&&length!=6)
rep.append("<br>Alert: Length should be 1, 2 or 6 bytes");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x6348524D) //cHRM
{
rep.append("<br>Primary chromaticities and white point");
rep.append("<br>NB data represents 4 points for white,red,green,blue");
rep.append("<br>x coordinates and y coordinates");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x67414D41) //gAMA
{
rep.append("<br>Image gamma value");
rep.append(("<br>"+get_dword(start+8)));
}
else if(typ == 0x68495354) //hIST
{
rep.append("<br>Image histogram");
rep.append("<br>Should be 2 bytes for each entry in PLTE");
rep.append(("<br>Contains " + (length/2) + " entries"));
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x70485973) //pHYs
{
rep.append("<br>Physical pixel dimensions");
rep.append("<br>Should be 9 bytes");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x73424954) //sBIT
{
rep.append("<br>Significant bits");
rep.append("<br>Should be 4 bytes or less");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x74455874) //tEXt
{
rep.append("<br>Text");
rep.append("<br>Consists of keyword and value separated by null byte");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x74494D45) //tIME
{
rep.append("<br>Last modification time");
rep.append(("<br>Year : "+png_get_word(start+8)));
rep.append(("<br>Month : "+uf(start+10)));
rep.append(("<br>Day : "+uf(start+11)));
rep.append(("<br>Hour : "+uf(start+12)));
rep.append(("<br>Minute: "+uf(start+13)));
rep.append(("<br>Second: "+uf(start+14)));
}
else if(typ == 0x74524E53) //tRNS
{
rep.append("<br>Transparency");
rep.append("<br>Alpha values, either for palette");
rep.append("<br> or single value for image");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else if(typ == 0x7a545874) //zTXt
{
rep.append("<br>Text, compressed");
rep.append("<br>Keyword is not compressed, value is compressed");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
else
{
rep.append("<br>Unknown chunk type");
rep.append("<br>dump of data:");
fdump(start+8,start+8+length-1);
}
return check_png_chunks(start+12+length);
}
/**
* Analysis particular to a bmp file
*/
private void analyse_bmp()
{
int fsz=get_dword(2);
int offbits=get_dword(10);
if(f.length<54)
{
rep.append("<br>File is too short to contain headers");
return;
}
rep.append("<br>File Header info:");
rep.append(("<br>File size: "+Integer.toHexString(fsz)));
rep.append(("<br>Reserved1: " + get_hword(6)));
rep.append(("<br>Reserved2: " + get_hword(8)));
if(f.length>fsz)
{
rep.append(("<br>Additional bytes at end of file = "+(f.length-fsz)));
rep.append(("<br>Dump of additional bytes:"));
fdump(fsz,f.length-1);
rep.append("<br>NB: Additional bytes may indicate that the height is set incorrectly" +
" in the header, try increasing the height to see if it is hiding image data");
}
rep.append(("<br>Bitmap data starts at: "+Integer.toHexString(offbits)));
rep.append(("<br>Info Header:"));
int bisize=get_dword(14);
rep.append(("<br>Info Size: " + Integer.toHexString(bisize)));
rep.append(("<br>Width: " + get_hdword(18) + " (" + get_dword(18) + ")"));
rep.append(("<br>Height: " + get_hdword(22) + " (" + get_dword(22) + ")"));
rep.append(("<br>Planes: " + get_hword(26) + " (must be 1)"));
rep.append(("<br>BitCount: " + get_hword(28)+ " bits per pixel"));
int compress = get_dword(30);
rep.append(("<br>Compression: " + get_hdword(30)));
if(compress==0x00||compress==0x32424752)
rep.append(" (No compression)");
else if(compress==0x01||compress==0x38454c52)
rep.append(" (RLE for 8bpp RGB)");
else if(compress==0x02||compress==0x34454c52)
rep.append(" (RLE for 4bpp RGB)");
else if(compress==0x03)
rep.append(" (Raw RGB with packing)");
else if(compress==0x32776173)
rep.append(" (Raw RGB)");
else if(compress==0x41424752)
rep.append(" (Raw RGB with alpha)");
else if(compress==0x54424752)
rep.append(" (Raw RGB with transparency)");
rep.append(("<br>Size Image: " + get_hdword(34) + " (can be zero if bitmap is uncompressed)"));
rep.append(("<br>XPelsPerMeter: " + get_hdword(38) + " (pixels per meter for target device)"));
rep.append(("<br>YPelsPerMeter: " + get_hdword(42) + " (pixels per meter for target device)"));
rep.append(("<br>ClrUsed: " + get_hdword(46) + " (color indexes in use, 0=max)"));
rep.append(("<br>ClrImportant: " + get_hdword(50) + "(0 if all colors are important)"));
int ctstart = 14+bisize;
rep.append(("<br>Color table computed start: "+Integer.toHexString(ctstart) + "(normally 0x36, if not then possible hidden data at that point)"));
if(ctstart>0x36)
{
rep.append("<br>Dump of gap between header and start of color table:");
fdump(0x36, ctstart-1);
}
if(get_word(28)<=8)
{
rep.append("<br>Color Index Table (NB fourth entry of each index should be zero, order is b,g,r,a):");
int ncols=get_dword(46);
if(ncols==0)
{
if(get_word(28)==1)ncols=2;
else if(get_word(28)==4)ncols=16;
else if(get_word(28)==8)ncols=256;
}
for(int i=0;i<ncols;i++)
{
rep.append("<br>");
for(int j=0;j<4;j++)
{
rep.append(m2(Integer.toHexString(uf(ctstart + i * 4 + j))));
rep.append(" ");
}
rep.append(" ");
for(int j=0;j<4;j++)
{
char c=(char)uf(ctstart + i * 4 + j);
if(c<32||c>0x7f)c='.';
rep.append((""+c));
}
}
ctstart+=ncols*4;
}
if(ctstart!=offbits)
{
rep.append(("<br>Color table finishes at " + Integer.toHexString(ctstart) +
" but data bits start at " + Integer.toHexString(offbits)));
}
if(ctstart<offbits)
{
rep.append("<br>Dump of gap between color table and image:");
fdump(ctstart, offbits-1);
}
if(compress!=0x00&&compress!=0x32424752)
{
rep.append("<br>Further checking is only done when there is no compression");
return;
}
rep.append("<br>Row filler bytes dump:");
// width * bits per pixel
int bitsPerRow=get_dword(18)*get_word(28);
int bytesPerRow = (bitsPerRow+7)/8;
int fgap = (bytesPerRow+3)/4;
fgap = fgap * 4 - bytesPerRow;
ctstart=offbits;
for(int i=0;i<get_dword(22);i++)
{
ctstart+=bytesPerRow;
int ctend=ctstart+fgap;
if(ctend!=ctstart)
fdump(ctstart,ctend-1);
ctstart=ctend;
}
}
/**
* Dumps a section of file
* @param from Dump from this offset
* @param to Dump to this offset
*/
private void fdump(int from, int to)
{
if(from>=f.length)
return;
rep.append("<br>Hex:");
for(int i=from;i<=to&&i<f.length;i+=16)
{
rep.append("<br>");
for(int j=0;j<16&&i+j<f.length&&i+j<=to;j++)
{
rep.append(m2(Integer.toHexString(((int)f[i+j])&0xff)));
if(j==7)
rep.append(' ');
}
rep.append(" ");
}
rep.append("<br>Ascii:");
for(int i=from;i<=to&&i<f.length;i+=16)
{
rep.append("<br>");
for(int j=0;j<16&&i+j<f.length&&i+j<=to;j++)
{
char c = (char)f[i+j];
if(c=='<') rep.append("&lt;");
else if(c=='>') rep.append("&gt;");
else if(c=='&') rep.append("&amp;");
else if(c >= 32 && c <= 128)
rep.append(c);
else
rep.append('.');
if(j==7) rep.append(' ');
}
}
}
/**
* Ensures a hex string is 2 bytes long, adding a leading zero if it is not
* @param hx hex string
* @return
*/
private String m2(String hx)
{
if(hx.length()<2)
return "0" + hx;
return hx;
}
/**
* Returns hex of dword at given file offset (lsb...msb)
* @param offs File offset
* @return Hex string
*/
private String get_hdword(int offs)
{
return Integer.toHexString(get_dword(offs));
}
/**
* Returns hex of dword at given file offset (msb...lsb)
* @param offs File offset
* @return Hex string
*/
private String png_get_hdword(int offs)
{
return Integer.toHexString(png_get_dword(offs));
}
/**
* Returns hex of word at given file offset (lsb...msb)
* @param offs File offset
* @return Hex string
*/
private String get_hword(int offs)
{
return Integer.toHexString(get_word(offs));
}
/**
* Returns byte at given file offset
* @param offs File offset
* @return byte at file offset, as int
*/
private int uf(int offs)
{
if(offs>=f.length)
return 0;
int r = f[offs];
return r&0xff;
}
/**
* Returns dword at given file offset (lsb...msb)
* @param offs File offset
* @return dword at file offset, as int
*/
private int get_dword(int offs)
{
if(offs+3>=f.length)
return 0;
return uf(offs)+(uf(offs+1)<<8)+(uf(offs+2)<<16)+(uf(offs+3)<<24);
}
/**
* Returns dword at given file offset (msb...lsb)
* @param offs File offset
* @return dword at file offset, as int
*/
private int png_get_dword(int offs)
{
if(offs+3>=f.length)
return 0;
return uf(offs+3)+(uf(offs+2)<<8)+(uf(offs+1)<<16)+(uf(offs)<<24);
}
/**
* Returns word at given file offset (lsb...msb)
* @param offs File offset
* @return word at file offset, as int
*/
private int get_word(int offs)
{
if(offs+1>=f.length)
return 0;
return uf(offs)+(uf(offs+1)<<8);
}
/**
* Returns word at given file offset (msb...lsb)
* @param offs File offset
* @return word at file offset, as int
*/
private int png_get_word(int offs)
{
if(offs+1>=f.length)
return 0;
return uf(offs+1)+(uf(offs)<<8);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
report = new javax.swing.JEditorPane();
jPanel2 = new javax.swing.JPanel();
OKButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("文件格式分析");
jPanel1.setMinimumSize(new java.awt.Dimension(400, 300));
jPanel1.setPreferredSize(new java.awt.Dimension(400, 350));
jScrollPane1.setMinimumSize(new java.awt.Dimension(400, 260));
jScrollPane1.setPreferredSize(new java.awt.Dimension(400, 260));
report.setContentType("text/html");
report.setFont(new java.awt.Font("微软雅黑", 0, 14)); // NOI18N
jScrollPane1.setViewportView(report);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 815, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
jPanel2.setMinimumSize(new java.awt.Dimension(400, 35));
jPanel2.setPreferredSize(new java.awt.Dimension(400, 35));
OKButton.setText("确认");
OKButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
OKButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
OKButtonActionPerformed(evt);
}
});
jPanel2.add(OKButton);
getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
pack();
}// </editor-fold>//GEN-END:initComponents
/**
* Close the form
* @param evt Event
*/
private void OKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKButtonActionPerformed
dispose();
}//GEN-LAST:event_OKButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton OKButton;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JEditorPane report;
// End of variables declaration//GEN-END:variables
}

262
stegsolve/FrameBrowser.java Normal file
View File

@@ -0,0 +1,262 @@
/*
* FrameBrowser.java
*/
package stegsolve;
import javax.swing.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import java.io.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.filechooser.*;
// todo: jphide checker/ invisible secrets
/**
* Frame Browser
* @author Caesum
*/
public class FrameBrowser extends JFrame
{
/**
* Label with the text showing the frame number
*/
private JLabel nowShowing;
/**
* Panel for the buttons
*/
private JPanel buttonPanel;
/**
* Forward button
*/
private JButton forwardButton;
/**
* Backward button
*/
private JButton backwardButton;
/**
* Save button
*/
private JButton saveButton;
/**
* Panel with image on it
*/
private DPanel dp;
/**
* Scroll pane for the image
*/
private JScrollPane scrollPane;
/**
* The image being viewed
*/
private BufferedImage bi = null;
/**
* The individual frames of the image
*/
private java.util.List<BufferedImage> frames = null;
/**
* Number of the current frame
*/
private int fnum=0;
/**
* Number of frames
*/
private int numframes=0;
/**
* Creates a new frame browser
* @param b The image the view
* @param f The file of the image
*/
public FrameBrowser(BufferedImage b, File f)
{
BufferedImage bnext;
bi = b;
initComponents();
fnum = 0;
numframes = 0;
frames = new ArrayList<BufferedImage>();
try
{
ImageInputStream ii = ImageIO.createImageInputStream(f);
if(ii==null) System.out.println("Couldn't create input stream");
ImageReader rr = ImageIO.getImageReaders(ii).next();
if(rr==null) System.out.println("No image reader");
rr.setInput(ii);
int fread = rr.getMinIndex();
while(true)
{
bnext = rr.read(numframes+fread);
if(bnext==null)
break;
frames.add(bnext);
numframes++;
}
System.out.println("总帧数 " + numframes);
}
catch (IOException e)
{
JOptionPane.showMessageDialog(this, "Failed to load file: " +e.toString());
}
catch(IndexOutOfBoundsException e)
{
// expected for reading too many frames
}
newImage();
}
// <editor-fold defaultstate="collapsed" desc="Initcomponents()">
private void initComponents() {
nowShowing = new JLabel();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
this.add(nowShowing, BorderLayout.NORTH);
buttonPanel = new JPanel();
backwardButton = new JButton("<");
backwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
backwardButtonActionPerformed(evt);
}
});
forwardButton = new JButton(">");
forwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
forwardButtonActionPerformed(evt);
}
});
saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
saveButtonActionPerformed(evt);
}
});
buttonPanel.add(backwardButton);
buttonPanel.add(forwardButton);
buttonPanel.add(saveButton);
add(buttonPanel, BorderLayout.SOUTH);
backwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0), "back");
backwardButton.getActionMap().put("back", backButtonPress);
forwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0), "forward");
forwardButton.getActionMap().put("forward", forwardButtonPress);
dp = new DPanel();
scrollPane = new JScrollPane(dp);
add(scrollPane, BorderLayout.CENTER);
pack();
//setResizable(false);
}// </editor-fold>
/**
* This is used to map the left arrow key to the back button
*/
private Action backButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ backwardButtonActionPerformed(e);}
};
/**
* Move back by one frame
* @param evt Event
*/
private void backwardButtonActionPerformed(ActionEvent evt) {
fnum--;
if(fnum<0)fnum=numframes-1;
updateImage();
}
/**
* This is used to map the right arrow key to the forward button
*/
private Action forwardButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ forwardButtonActionPerformed(e);}
};
/**
* Move forward by one frame
* @param evt Event
*/
private void forwardButtonActionPerformed(ActionEvent evt) {
fnum++;
if(fnum>=numframes)fnum=0;
updateImage();
}
/**
* Save the current frame
* @param evt Event
*/
private void saveButtonActionPerformed(ActionEvent evt)
{
File sfile = null;
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Images", "jpg", "gif", "png", "bmp");
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File("frame"+(fnum+1)+".bmp"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if(rVal == JFileChooser.APPROVE_OPTION)
{
sfile = fileChooser.getSelectedFile();
try
{
BufferedImage bbx = frames.get(fnum);
int rns = sfile.getName().lastIndexOf(".")+1;
if(rns==0)
ImageIO.write(bbx, "bmp", sfile);
else
ImageIO.write(bbx, sfile.getName().substring(rns), sfile);
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "Failed to write file: "+e.toString());
}
}
}
/**
* Update the text description and repaint the image
*/
private void updateImage()
{
nowShowing.setText("Frame : " + (fnum+1) + " of " + numframes);
if(numframes==0) return;
dp.setImage(frames.get(fnum));
repaint();
}
/**
* Show the image and make sure the frame browser looks right
*/
private void newImage()
{
nowShowing.setText("Frame : " + (fnum+1) + " of " + numframes);
if(numframes==0) return;
dp.setImage(frames.get(fnum));
dp.setSize(bi.getWidth(),bi.getHeight());
dp.setPreferredSize(new Dimension(bi.getWidth(),bi.getHeight()));
this.setMaximumSize(getToolkit().getScreenSize());
pack();
dp.apply(100);
scrollPane.revalidate();
repaint();
this.setSize(500, 600);
}
}

484
stegsolve/StegSolve.java Normal file
View File

@@ -0,0 +1,484 @@
/*
* StegSolve.java
*
* Created on 18-Apr-2011, 08:48:02
*/
package stegsolve;
import com.formdev.flatlaf.FlatIntelliJLaf;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.*;
import java.io.*;
import java.awt.image.*;
import javax.imageio.*;
import java.awt.event.*;
import java.awt.*;
// todo - sort out dimensions in linux
// todo - width/height explorer
/**
* StegSolve
*
* @author Caesum
*/
public class StegSolve extends JFrame {
static StegSolve that;
/**
* Menu option - about
*/
private JMenuItem about;
/**
* Menu option - file exit
*/
private JMenuItem fileExit;
/**
* Menu option - file save
*/
private JMenuItem fileSave;
/**
* Menu option - file save
*/
private JMenuItem fileOpen;
/**
* Menu option - analyse format
*/
private JMenuItem analyseFormat;
/**
* Menu option - extract data
*/
private JMenuItem analyseExtract;
/**
* Menu option - solve stereogram
*/
private JMenuItem stereoSolve;
/**
* Menu option - frame browser
*/
private JMenuItem frameBrowse;
/**
* Menu option - frame browser
*/
private JMenuItem imageCombine;
/**
* Menu bar
*/
private JMenuBar menuBar;
/**
* Sub menu - file
*/
private JMenu menuFile;
/**
* Sub menu - analyse
*/
private JMenu menuAnalyse;
/**
* Sub menu - help
*/
private JMenu menuHelp;
/**
* label that shows the number of the frame currently being shown
*/
private JLabel nowShowing;
/**
* panel for buttons
*/
private JPanel buttonPanel;
private ZoomSlider zoomSlider;
/**
* Next frame button
*/
private JButton forwardButton;
/**
* Previous frame button
*/
private JButton backwardButton;
/**
* Panel with image on it
*/
private DPanel dp;
/**
* Scroll bars for panel with image
*/
private JScrollPane scrollPane;
/**
* The image file
*/
private File sfile = null;
/**
* The image
*/
private BufferedImage bi = null;
/**
* The transformation being viewed
*/
private Transform transform = null;
/**
* Creates new form stegsolve
*/
private StegSolve() {
that = this;
initComponents();
}
// <editor-fold defaultstate="collapsed" desc="Initcomponents()">
private void initComponents() {
FlatIntelliJLaf.install();
menuBar = new JMenuBar();
menuFile = new JMenu();
fileOpen = new JMenuItem();
fileSave = new JMenuItem();
fileExit = new JMenuItem();
menuAnalyse = new JMenu();
analyseFormat = new JMenuItem();
analyseExtract = new JMenuItem();
stereoSolve = new JMenuItem();
frameBrowse = new JMenuItem();
imageCombine = new JMenuItem();
menuHelp = new JMenu();
about = new JMenuItem();
nowShowing = new JLabel();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
menuFile.setText("文件");
fileOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
fileOpen.setText("打开");
fileOpen.addActionListener(this::fileOpenActionPerformed);
menuFile.add(fileOpen);
fileSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0));
fileSave.setText("另存为");
fileSave.addActionListener(this::fileSaveActionPerformed);
menuFile.add(fileSave);
fileExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0));
fileExit.setText("退出");
fileExit.addActionListener(this::fileExitActionPerformed);
menuFile.add(fileExit);
menuBar.add(menuFile);
menuAnalyse.setText("分析");
analyseFormat.setText("文件格式");
analyseFormat.addActionListener(this::analyseFormatActionPerformed);
menuAnalyse.add(analyseFormat);
analyseExtract.setText("数据提取");
analyseExtract.addActionListener(this::analyseExtractActionPerformed);
menuAnalyse.add(analyseExtract);
stereoSolve.setText("立体视图");
stereoSolve.addActionListener(this::stereoSolveActionPerformed);
menuAnalyse.add(stereoSolve);
frameBrowse.setText("帧浏览器");
frameBrowse.addActionListener(this::frameBrowseActionPerformed);
menuAnalyse.add(frameBrowse);
imageCombine.setText("图像合成器");
imageCombine.addActionListener(this::imageCombineActionPerformed);
menuAnalyse.add(imageCombine);
menuBar.add(menuAnalyse);
menuHelp.setText("帮助");
about.setText("关于");
about.addActionListener(this::aboutActionPerformed);
menuHelp.add(about);
menuBar.add(menuHelp);
setJMenuBar(menuBar);
setLayout(new BorderLayout());
JPanel textZoom = new JPanel();
textZoom.setLayout(new BorderLayout());
textZoom.add(nowShowing, BorderLayout.NORTH);
buttonPanel = new JPanel();
backwardButton = new JButton("<");
backwardButton.addActionListener(this::backwardButtonActionPerformed);
forwardButton = new JButton(">");
forwardButton.addActionListener(this::forwardButtonActionPerformed);
buttonPanel.add(backwardButton);
buttonPanel.add(forwardButton);
add(buttonPanel, BorderLayout.SOUTH);
zoomSlider = new ZoomSlider(10, 1000, 100);
zoomSlider.addChangeListener(v -> {
dp.apply(v);
dp.revalidate();
});
textZoom.add(zoomSlider, BorderLayout.SOUTH);
add(textZoom, BorderLayout.NORTH);
dp = new DPanel();
scrollPane = new JScrollPane(dp);
//Horizontal scrolling
JFrame frame = this;
frame.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.isShiftDown()) {
frame.addMouseWheelListener(arg01 -> {
// TODO Auto-generated method stub
scrollPane.getHorizontalScrollBar().setValue(scrollPane.getHorizontalScrollBar().getValue() + arg01.getWheelRotation());
});
}
}
@Override
public void keyReleased(KeyEvent e) {
if (!e.isShiftDown()) {
frame.removeMouseWheelListener(frame.getMouseWheelListeners()[0]);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
});
add(scrollPane, BorderLayout.CENTER);
backwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "back");
backwardButton.getActionMap().put("back", backButtonPress);
forwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "forward");
forwardButton.getActionMap().put("forward", forwardButtonPress);
this.setTitle("StegSolve 1.5 by Souno (龙腾四季专版)");
this.setMaximumSize(getToolkit().getScreenSize());
pack();
this.setSize(800, 600);
//setResizable(false);
}// </editor-fold>
/**
* Close the form on file exit
*
* @param evt Event
*/
private void fileExitActionPerformed(ActionEvent evt) {
dispose();
}
/**
* This is used to map the left arrow key to the back button
*/
private Action backButtonPress = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
backwardButtonActionPerformed(e);
}
};
/**
* Move back by one image
*
* @param evt Event
*/
private void backwardButtonActionPerformed(ActionEvent evt) {
if (transform == null) return;
transform.back();
updateImage();
}
/**
* This is used to map the right arrow key to the forward button
*/
private Action forwardButtonPress = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
forwardButtonActionPerformed(e);
}
};
/**
* Move forward by one image
*
* @param evt Event
*/
private void forwardButtonActionPerformed(ActionEvent evt) {
if (bi == null) return;
transform.forward();
updateImage();
}
/**
* Show the help/about frame
*
* @param evt Event
*/
private void aboutActionPerformed(ActionEvent evt) {
new AboutFrame().setVisible(true);
}
/**
* Open the file format analyser
*
* @param evt Event
*/
private void analyseFormatActionPerformed(ActionEvent evt) {
new FileAnalysis(sfile).setVisible(true);
}
/**
* Open the stereogram solver
*
* @param evt Event
*/
private void stereoSolveActionPerformed(ActionEvent evt) {
new Stereo(bi).setVisible(true);
}
/**
* Open the frame browser
*
* @param evt Event
*/
private void frameBrowseActionPerformed(ActionEvent evt) {
new FrameBrowser(bi, sfile).setVisible(true);
}
/**
* Open the image combiner
*
* @param evt Event
*/
private void imageCombineActionPerformed(ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
FileNameExtensionFilter filter = new FileNameExtensionFilter("Images", "jpg", "jpeg", "gif", "bmp", "png");
fileChooser.setFileFilter(filter);
fileChooser.setDialogTitle("选择要合并的图像");
int rVal = fileChooser.showOpenDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if (rVal == JFileChooser.APPROVE_OPTION) {
sfile = fileChooser.getSelectedFile();
try {
BufferedImage bi2 = null;
bi2 = ImageIO.read(sfile);
new Combiner(bi, bi2).setVisible(true);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "加载文件失败: " + e.toString());
}
}
}
/**
* Open the data extractor
*
* @param evt Event
*/
private void analyseExtractActionPerformed(ActionEvent evt) {
new Extract(bi).setVisible(true);
}
/**
* Save the current transformed image
*
* @param evt Event
*/
private void fileSaveActionPerformed(ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
fileChooser.setSelectedFile(new File("solved.bmp"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if (rVal == JFileChooser.APPROVE_OPTION) {
sfile = fileChooser.getSelectedFile();
try {
bi = transform.getImage();
int rns = sfile.getName().lastIndexOf(".") + 1;
if (rns == 0)
ImageIO.write(bi, "bmp", sfile);
else
ImageIO.write(bi, sfile.getName().substring(rns), sfile);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "写入文件失败: " + e.toString());
}
}
}
/**
* Open a file
*
* @param evt Event
*/
private void fileOpenActionPerformed(ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
FileNameExtensionFilter filter = new FileNameExtensionFilter("Images", "jpg", "jpeg", "gif", "bmp", "png");
fileChooser.setFileFilter(filter);
int rVal = fileChooser.showOpenDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if (rVal == JFileChooser.APPROVE_OPTION) {
sfile = fileChooser.getSelectedFile();
loadImage(sfile);
}
}
public void loadImage(String path) {
File sfile = new File(path);
loadImage(sfile);
}
void loadImage(File sfile) {
this.sfile = sfile;
try {
bi = ImageIO.read(sfile);
transform = new Transform(bi);
newImage();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "加载文件失败: " + e.toString());
}
}
/**
* Reset settings for a new image
*/
private void newImage() {
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
dp.setSize(transform.getImage().getWidth(), transform.getImage().getHeight());
dp.setPreferredSize(new Dimension(transform.getImage().getWidth(), transform.getImage().getHeight()));
this.setMaximumSize(getToolkit().getScreenSize());
zoomSlider.setValue(100);
dp.apply(100);
scrollPane.revalidate();
repaint();
}
/**
* Update the image being shown for new transform
*/
private void updateImage() {
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
repaint();
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
EventQueue.invokeLater(() -> new StegSolve().setVisible(true));
}
}

222
stegsolve/Stereo.java Normal file
View File

@@ -0,0 +1,222 @@
/*
* Stereo.java
*/
package stegsolve;
import javax.swing.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.filechooser.*;
import java.io.*;
import javax.imageio.*;
/**
* Stereogram solver
* @author Caesum
*/
public class Stereo extends JFrame
{
/**
* Label showing the current offset
*/
private JLabel nowShowing;
/**
* Panel for buttons
*/
private JPanel buttonPanel;
/**
* Increase offset button
*/
private JButton forwardButton;
/**
* Decrease offset button
*/
private JButton backwardButton;
/**
* Save image button
*/
private JButton saveButton;
/**
* Panel containing image
*/
private DPanel dp;
/**
* Scroll bars for image
*/
private JScrollPane scrollPane;
/**
* The image being solved
*/
private BufferedImage bi = null;
/**
* The image after transformation
*/
private StereoTransform transform = null;
/**
* The current offset being tried
*/
private int inum=0;
/**
* Creates new form Stereo
* @param b The image to solve
*/
public Stereo(BufferedImage b)
{
bi = b;
initComponents();
transform = new StereoTransform(bi);
newImage();
}
// <editor-fold defaultstate="collapsed" desc="Initcomponents()">
private void initComponents() {
nowShowing = new JLabel();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
this.add(nowShowing, BorderLayout.NORTH);
buttonPanel = new JPanel();
backwardButton = new JButton("<");
backwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
backwardButtonActionPerformed(evt);
}
});
forwardButton = new JButton(">");
forwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
forwardButtonActionPerformed(evt);
}
});
saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
saveButtonActionPerformed(evt);
}
});
buttonPanel.add(backwardButton);
buttonPanel.add(forwardButton);
buttonPanel.add(saveButton);
add(buttonPanel, BorderLayout.SOUTH);
backwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0), "back");
backwardButton.getActionMap().put("back", backButtonPress);
forwardButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0), "forward");
forwardButton.getActionMap().put("forward", forwardButtonPress);
dp = new DPanel();
scrollPane = new JScrollPane(dp);
add(scrollPane, BorderLayout.CENTER);
pack();
//setResizable(false);
}// </editor-fold>
/**
* This is used to map the left arrow key to the back button
*/
private Action backButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ backwardButtonActionPerformed(e);}
};
/**
* Move back by one offset
* @param evt Event
*/
private void backwardButtonActionPerformed(ActionEvent evt) {
if(transform == null) return;
transform.back();
updateImage();
}
/**
* This is used to map the right arrow key to the forward button
*/
private Action forwardButtonPress = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{ forwardButtonActionPerformed(e);}
};
/**
* Move forward by one offset
* @param evt Event
*/
private void forwardButtonActionPerformed(ActionEvent evt) {
if(bi == null) return;
transform.forward();
updateImage();
}
/**
* Save the current image
* @param evt Event
*/
private void saveButtonActionPerformed(ActionEvent evt)
{
File sfile = null;
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Images", "jpg", "gif", "png", "bmp");
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File("solved.bmp"));
int rVal = fileChooser.showSaveDialog(this);
System.setProperty("user.dir", fileChooser.getCurrentDirectory().getAbsolutePath());
if(rVal == JFileChooser.APPROVE_OPTION)
{
sfile = fileChooser.getSelectedFile();
try
{
BufferedImage bbx = transform.getImage();
int rns = sfile.getName().lastIndexOf(".")+1;
if(rns==0)
ImageIO.write(bbx, "bmp", sfile);
else
ImageIO.write(bbx, sfile.getName().substring(rns), sfile);
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "Failed to write file: "+e.toString());
}
}
}
/**
* Update the text description and repaint the image
*/
private void updateImage()
{
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
repaint();
}
/**
* Show the image and make sure the form looks right
*/
private void newImage()
{
nowShowing.setText(transform.getText());
dp.setImage(transform.getImage());
dp.setSize(transform.getImage().getWidth(),transform.getImage().getHeight());
dp.setPreferredSize(new Dimension(transform.getImage().getWidth(),transform.getImage().getHeight()));
this.setMaximumSize(getToolkit().getScreenSize());
pack();
scrollPane.revalidate();
dp.apply(100);
repaint();
this.setSize(500, 600);
}
}

View File

@@ -0,0 +1,92 @@
/*
* StereoTransform.java
*/
package stegsolve;
import java.awt.image.*;
/**
* Represents solving a stereogram
* @author Caesum
*/
public class StereoTransform {
/**
* Original image
*/
private BufferedImage originalImage;
/**
* Transformed image
*/
private BufferedImage transform;
/**
* Offset of transformation
*/
private int transNum;
/**
* Create a new transformation
* @param bi Image
*/
StereoTransform(BufferedImage bi)
{
originalImage = bi;
transNum=0;
calcTrans();
}
/**
* Solve the stereogram given the offset
*/
private void calcTrans()
{
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
col=fcol^(originalImage.getRGB((i+transNum)%originalImage.getWidth(), j)&0x00ffffff);
transform.setRGB(i, j, col);
}
}
/**
* Reduce the offset and try to solve
*/
public void back()
{
transNum--;
if(transNum<0) transNum=originalImage.getWidth()-1;
calcTrans();
}
/**
* Increase the offset and try to solve
*/
public void forward()
{
transNum++;
if(transNum>=originalImage.getWidth()) transNum=0;
calcTrans();
}
/**
* Text description for offset
* @return string text description of offset
*/
public String getText()
{
return "偏移量: "+transNum;
}
/**
* The transformed image
* @return buffered image of the stereogram with transformation
*/
public BufferedImage getImage()
{
return transform;
}
}

446
stegsolve/Transform.java Normal file
View File

@@ -0,0 +1,446 @@
/*
* Transform.java
*/
/*
* transforms
* 0 - none
* 1 - inversion
* 2-9 - alpha planes
* 10-17 - r planes
* 18-25 - g planes
* 26-33 - b planes
* 34 full alpha
* 35 full red
* 36 full green
* 37 full blue
* 38 random color1
* 39 random color2
* 40 random color3
* 41 gray bits
*/
package stegsolve;
import java.awt.image.*;
import java.util.Random;
/**
* A transform represents a change to the image such as a bit plane
* or recolouring etc
* @author Caesum
*/
public class Transform {
/**
* Original image
*/
private BufferedImage originalImage;
/**
* Transformed image
*/
private BufferedImage transform;
/**
* The number of this transformation
*/
private int transNum;
/**
* The number of transformations supported
*/
private static final int MAXTRANS = 41;
/**
* Create a new transformation
* @param bi the image
*/
Transform(BufferedImage bi)
{
originalImage = bi;
transform = originalImage;
transNum=0;
}
/**
* Makes an image from a bit plane
* @param d bit to use
*/
private void transfrombit(int d)
{
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
if(((fcol>>>d)&1)>0)
col=0xffffff;
transform.setRGB(i, j, col);
}
}
/**
* Makes an image given a mask of bit planes
* @param mask bit mask to use
*/
private void transmask(int mask)
{
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
col=fcol&mask;
if(col>0xffffff||col<0)
col=col>>>8;
transform.setRGB(i, j, col);
}
}
/**
* Inverts the colours of the image
*/
private void inversion()
{
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
col=fcol^0xffffff;
transform.setRGB(i, j, col);
}
}
/**
* Highlights just the pixels for which r=g=b
*/
private void graybits()
{
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
if((fcol&0xff)==((fcol&0xff00)>>8)&&(fcol&0xff)==((fcol&0xff0000)>>16))
col=0xffffff;
transform.setRGB(i, j, col);
}
}
/**
* Randomises the colours of the image for a truecolour image
*/
private void random_colormap()
{
// straight random mapping
Random rnd = new Random();
int bm = rnd.nextInt(256),ba = rnd.nextInt(256),bx = rnd.nextInt(256);
int gm = rnd.nextInt(256),ga = rnd.nextInt(256),gx = rnd.nextInt(256);
int rm = rnd.nextInt(256),ra = rnd.nextInt(256),rx = rnd.nextInt(256);
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_RGB);
for(int i=0;i<originalImage.getWidth();i++)
for(int j=0;j<originalImage.getHeight();j++)
{
int col=0;
int fcol = originalImage.getRGB(i,j);
int b = (fcol & 0xff) * bm;
b = ((b*bm)^bx)+ba;
int g = ((fcol & 0xff00)>>8) * gm;
g = ((g*gm)^gx)+ga;
int r = ((fcol & 0xff0000)>>16) * rm;
r = ((r*rm)^rx)+ra;
col = (r<<16)+(g<<8)+b+(fcol&0xff000000);
transform.setRGB(i, j, col);
}
}
/**
* Randomises the colours of the image for an indexed palette image
*/
private void random_indexmap()
{
// this would be an indexed palette - this is separate
// because two indexes can have the same color value
// so the mapping should be done on the palette and not
// on the image itself
byte [] r, g, b;
int bits, size;
int [] gcs;
Random rnd = new Random();
IndexColorModel cm = (IndexColorModel)originalImage.getColorModel();
gcs = cm.getComponentSize();
bits = gcs[0];
if(gcs[1]>bits) bits=gcs[1];
if(gcs[2]>bits) bits=gcs[2];
size = cm.getMapSize();
r = new byte[size];
g = new byte[size];
b = new byte[size];
cm.getReds(r);
cm.getGreens(g);
cm.getBlues(b);
for(int i=0;i<size;i++)
{
r[i]=(byte)rnd.nextInt(256);
g[i]=(byte)rnd.nextInt(256);
b[i]=(byte)rnd.nextInt(256);
}
transform = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, new IndexColorModel(bits, size, r, g, b));
transform.setData(originalImage.getRaster());
}
/**
* Randomises the colours of the image
* depending on the type of image
*/
private void randommap()
{
ColorModel cm = originalImage.getColorModel();
if(cm instanceof ComponentColorModel)
random_colormap();
else if(cm instanceof IndexColorModel)
random_indexmap();
else if(cm instanceof PackedColorModel)
random_colormap();
}
/**
* Calculates the current image transformation
*/
private void calcTrans()
{
switch(transNum)
{
case 0:
transform = originalImage;
return;
case 1:
inversion();
return;
case 2:
transfrombit(31);
return;
case 3:
transfrombit(30);
return;
case 4:
transfrombit(29);
return;
case 5:
transfrombit(28);
return;
case 6:
transfrombit(27);
return;
case 7:
transfrombit(26);
return;
case 8:
transfrombit(25);
return;
case 9:
transfrombit(24);
return;
case 10:
transfrombit(23);
return;
case 11:
transfrombit(22);
return;
case 12:
transfrombit(21);
return;
case 13:
transfrombit(20);
return;
case 14:
transfrombit(19);
return;
case 15:
transfrombit(18);
return;
case 16:
transfrombit(17);
return;
case 17:
transfrombit(16);
return;
case 18:
transfrombit(15);
return;
case 19:
transfrombit(14);
return;
case 20:
transfrombit(13);
return;
case 21:
transfrombit(12);
return;
case 22:
transfrombit(11);
return;
case 23:
transfrombit(10);
return;
case 24:
transfrombit(9);
return;
case 25:
transfrombit(8);
return;
case 26:
transfrombit(7);
return;
case 27:
transfrombit(6);
return;
case 28:
transfrombit(5);
return;
case 29:
transfrombit(4);
return;
case 30:
transfrombit(3);
return;
case 31:
transfrombit(2);
return;
case 32:
transfrombit(1);
return;
case 33:
transfrombit(0);
return;
case 34:
transmask(0xff000000);
return;
case 35:
transmask(0x00ff0000);
return;
case 36:
transmask(0x0000ff00);
return;
case 37:
transmask(0x000000ff);
return;
case 38:
randommap();
return;
case 39:
randommap();
return;
case 40:
randommap();
return;
case 41:
graybits();
return;
default:
transform = originalImage;
return;
}
}
/**
* Select the previous transformation
*/
public void back()
{
transNum--;
if(transNum<0) transNum=MAXTRANS;
calcTrans();
}
/**
* Select the next transformation
*/
public void forward()
{
transNum++;
if(transNum>MAXTRANS) transNum=0;
calcTrans();
}
/**
* Return a textual description of the transformation
* @return text description for transformation
*/
public String getText()
{
switch(transNum)
{
case 0:
return "正常图像";
case 1:
return "颜色反转 (Xor)";
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
return "Alpha plane " + (9 - transNum);
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
return "Red plane " + (17 - transNum);
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
return "Green plane " + (25 - transNum);
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
return "Blue plane " + (33 - transNum);
case 34:
return "Full alpha";
case 35:
return "Full red";
case 36:
return "Full green";
case 37:
return "Full blue";
case 38:
return "Random colour map 1";
case 39:
return "Random colour map 2";
case 40:
return "Random colour map 3";
case 41:
return "灰度";
default:
return "";
}
}
/**
* Get the transformed image
* @return transformed image
*/
public BufferedImage getImage()
{
return transform;
}
}

66
stegsolve/ZoomSlider.java Normal file
View File

@@ -0,0 +1,66 @@
package stegsolve;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
public class ZoomSlider extends JPanel {
private JSlider slider;
private JTextField textBox;
private int value;
public int getValue () { return value; }
void setValue(int value) {
slider.setValue(value);
textBox.setText(String.valueOf(value));
this.value = value;
for (SliderChangeListener scl : changeListeners)
scl.change(value);
}
private List<SliderChangeListener> changeListeners = new ArrayList<>();
ZoomSlider(int min, int max, int defaultValue) {
JLabel tip = new JLabel("缩放:");
add(tip);
slider = new JSlider(min, max, defaultValue);
slider.addChangeListener(e -> {
setValue(slider.getValue());
});
add(slider);
textBox = new JTextField(String.valueOf(defaultValue), 5);
textBox.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
setValue(Integer.parseInt(textBox.getText()));
}
}
});
slider.setMaximumSize(new Dimension(500, 25));
add(textBox);
value = defaultValue;
}
void addChangeListener(SliderChangeListener listener) {
changeListeners.add(listener);
}
}
interface SliderChangeListener {
void change(int v);
}