1 /*
2 * steghide 0.5.1 - a steganography program
3 * Copyright (C) 1999-2003 Stefan Hetzl <shetzl@chello.at>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21 #include "common.h"
22
23 #ifdef USE_LIBJPEG
24
25 #include <cstdio>
26 #include <iostream>
27
28 #include "AUtils.h"
29 #include "BinaryIO.h"
30 #include "JpegFile.h"
31 #include "JpegSampleValue.h"
32 #include "SMDConstructionHeuristic.h"
33 #include "error.h"
34
JpegFile(BinaryIO * io)35 JpegFile::JpegFile (BinaryIO* io)
36 : CvrStgFile()
37 {
38 setSamplesPerVertex (SamplesPerVertex) ;
39 setRadius (Radius) ;
40 setEmbValueModulus (EmbValueModulus) ;
41 HeightInBlocks = NULL ;
42 WidthInBlocks = NULL ;
43 read (io) ;
44 }
45
~JpegFile()46 JpegFile::~JpegFile ()
47 {
48 if (WidthInBlocks) {
49 delete[] WidthInBlocks ;
50 }
51 if (HeightInBlocks) {
52 delete[] HeightInBlocks ;
53 }
54 }
55
getProperties() const56 std::list<CvrStgFile::Property> JpegFile::getProperties () const
57 {
58 std::list<CvrStgFile::Property> retval ;
59
60 // format
61 retval.push_back (CvrStgFile::Property (_("format"), "jpeg")) ;
62
63 return retval ;
64 }
65
read(BinaryIO * io)66 void JpegFile::read (BinaryIO* io)
67 {
68 CvrStgFile::read (io) ;
69
70 // TODO - use BinaryIO (or similar class) as input/output module for libjpeg (to avoid the NotImplementedError and using FILE* here)
71 FILE *infile = NULL ;
72 if (io->is_std()) {
73 throw NotImplementedError (_("can not use standard input as source for jpeg files with libjpeg.")) ;
74 }
75 else {
76 infile = io->getStream() ;
77 rewind (infile) ;
78 }
79
80 struct jpeg_error_mgr errmgr ;
81 DeCInfo.err = jpeg_std_error (&errmgr) ;
82 jpeg_create_decompress (&DeCInfo) ;
83 jpeg_stdio_src (&DeCInfo, infile) ;
84 jpeg_read_header (&DeCInfo, TRUE) ;
85
86 DctCoeffs = jpeg_read_coefficients (&DeCInfo) ;
87
88 // fill HeightInBlocks and WidthInBlocks
89 unsigned short max_v_samp_factor = 0 ;
90 unsigned short max_h_samp_factor = 0 ;
91 for (unsigned short icomp = 0 ; icomp < DeCInfo.num_components ; icomp++) {
92 max_v_samp_factor = AUtils::max<unsigned short> (max_v_samp_factor, DeCInfo.comp_info[icomp].v_samp_factor) ;
93 max_h_samp_factor = AUtils::max<unsigned short> (max_h_samp_factor, DeCInfo.comp_info[icomp].h_samp_factor) ;
94 }
95 HeightInBlocks = new unsigned int[DeCInfo.num_components] ;
96 WidthInBlocks = new unsigned int[DeCInfo.num_components] ;
97 for (unsigned short icomp = 0 ; icomp < DeCInfo.num_components ; icomp++) {
98 HeightInBlocks[icomp] = AUtils::div_roundup<unsigned int> (DeCInfo.image_height * DeCInfo.comp_info[icomp].v_samp_factor,
99 8 * max_v_samp_factor) ;
100 WidthInBlocks[icomp] = AUtils::div_roundup<unsigned int> (DeCInfo.image_width * DeCInfo.comp_info[icomp].h_samp_factor,
101 8 * max_h_samp_factor) ;
102 }
103
104 // resize LinDctCoeffs to size that is enough to contain all dct coeffs
105 unsigned long totalnumcoeffs = 0 ;
106 for (unsigned short icomp = 0 ; icomp < DeCInfo.num_components ; icomp++) {
107 totalnumcoeffs += CoeffPerBlock * (HeightInBlocks[icomp] * WidthInBlocks[icomp]) ;
108 }
109 LinDctCoeffs.resize (totalnumcoeffs) ;
110
111 // read data from jpeglib's virtual array into LinDctCoeffs and StegoIndices
112 UWORD32 linindex = 0 ;
113 for (unsigned short icomp = 0 ; icomp < DeCInfo.num_components ; icomp++) {
114 unsigned int currow = 0 ;
115 while (currow < HeightInBlocks[icomp]) {
116 unsigned int naccess = 1 ;
117 JBLOCKARRAY array = (*(DeCInfo.mem->access_virt_barray))
118 ((j_common_ptr) &DeCInfo, DctCoeffs[icomp], currow, naccess, FALSE) ;
119 for (unsigned int irow = 0 ; irow < naccess ; irow++) {
120 for (unsigned int iblock = 0 ; iblock < WidthInBlocks[icomp] ; iblock++) {
121 for (unsigned int icoeff = 0 ; icoeff < CoeffPerBlock ; icoeff++) {
122 LinDctCoeffs[linindex] = array[irow][iblock][icoeff] ;
123
124 // don't use zero dct coefficients to embed data
125 if (LinDctCoeffs[linindex] != 0) {
126 StegoIndices.push_back (linindex) ;
127 }
128 linindex++ ;
129 }
130 }
131 }
132 currow += naccess ;
133 }
134 }
135 }
136
write()137 void JpegFile::write ()
138 {
139 CvrStgFile::write() ;
140
141 FILE* outfile = getBinIO()->getStream() ;
142
143 // prepare for writing
144 jpeg_create_compress (&CInfo) ;
145 jpeg_copy_critical_parameters (&DeCInfo, &CInfo) ;
146 struct jpeg_error_mgr jerr2 ;
147 CInfo.err = jpeg_std_error(&jerr2) ;
148 jpeg_stdio_dest (&CInfo, outfile) ;
149
150 // write file header
151 jpeg_write_coefficients (&CInfo, DctCoeffs) ;
152
153 UWORD32 linindex = 0 ;
154 for (unsigned short icomp = 0 ; icomp < CInfo.num_components ; icomp++) {
155
156 unsigned int currow = 0 ;
157 while (currow < HeightInBlocks[icomp]) {
158 unsigned int naccess = 1 ;
159 JBLOCKARRAY array = (*(CInfo.mem->access_virt_barray))
160 ((j_common_ptr) &CInfo, DctCoeffs[icomp], currow, naccess, TRUE) ;
161 for (unsigned int irow = 0 ; irow < naccess ; irow++) {
162 for (unsigned int iblock = 0 ; iblock < WidthInBlocks[icomp] ; iblock++) {
163 for (unsigned int icoeff = 0 ; icoeff < CoeffPerBlock ; icoeff++) {
164 array[irow][iblock][icoeff] = LinDctCoeffs[linindex] ;
165 linindex++ ;
166 }
167 }
168 }
169 currow += naccess ;
170 }
171 }
172
173 // write and deallocate everything (writing is possible only once)
174 jpeg_finish_compress (&CInfo) ;
175 jpeg_destroy_compress(&CInfo);
176 jpeg_finish_decompress (&DeCInfo) ;
177 jpeg_destroy_decompress(&DeCInfo);
178 }
179
getNumSamples(void) const180 unsigned long JpegFile::getNumSamples (void) const
181 {
182 return StegoIndices.size() ;
183 }
184
getSampleValue(const SamplePos pos) const185 SampleValue* JpegFile::getSampleValue (const SamplePos pos) const
186 {
187 myassert (pos < StegoIndices.size()) ;
188 return new JpegSampleValue (LinDctCoeffs[StegoIndices[pos]]) ;
189 }
190
replaceSample(const SamplePos pos,const SampleValue * s)191 void JpegFile::replaceSample (const SamplePos pos, const SampleValue* s)
192 {
193 const JpegSampleValue* sample = dynamic_cast<const JpegSampleValue*> (s) ;
194 myassert (sample != NULL) ;
195 myassert (pos <= StegoIndices.size()) ;
196 LinDctCoeffs[StegoIndices[pos]] = sample->getDctCoeff() ;
197 }
198
getEmbeddedValue(const SamplePos pos) const199 EmbValue JpegFile::getEmbeddedValue (const SamplePos pos) const
200 {
201 myassert (pos < StegoIndices.size()) ;
202 return JpegSampleValue::calcEValue (LinDctCoeffs[StegoIndices[pos]]) ;
203 }
204
getMatchingAlgorithms(Graph * g,Matching * m) const205 std::vector<MatchingAlgorithm*> JpegFile::getMatchingAlgorithms (Graph* g, Matching* m) const
206 {
207 std::vector<MatchingAlgorithm*> retval ;
208 retval.push_back (new SMDConstructionHeuristic (g, m)) ;
209 return retval ;
210 }
211
212 #ifdef DEBUG
getFrequencies()213 std::map<SampleKey,unsigned long>* JpegFile::getFrequencies ()
214 {
215 unsigned long n = LinDctCoeffs.size() ;
216 std::map<SampleKey,unsigned long>* table = new std::map<SampleKey,unsigned long> () ;
217
218 for (unsigned long pos = 0 ; pos < n ; pos++) {
219 SampleValue *sv = (SampleValue*) new JpegSampleValue (LinDctCoeffs[pos]) ;
220 (*table)[sv->getKey()]++ ;
221 delete sv ;
222 }
223
224 return table ;
225 }
226
printFrequencies(const std::map<SampleKey,unsigned long> & freqs)227 void JpegFile::printFrequencies (const std::map<SampleKey,unsigned long>& freqs)
228 {
229 std::list<std::string> output ;
230
231 // insert the positive dct coeffs into output list
232 for (std::map<SampleKey,unsigned long>::const_iterator pit = freqs.begin() ; pit->first < 2147483648UL /* 2^31 */ ; pit++) {
233 char buf[30] ;
234 sprintf (buf, "%ld: %lu", (long) pit->first, pit->second) ;
235 output.push_back (std::string(buf)) ;
236 }
237
238 // insert the negative dct coeffs into output list
239 for (std::map<SampleKey,unsigned long>::const_reverse_iterator nit = freqs.rbegin() ; nit->first > 2147483648UL /* 2^31 */ ; nit++) {
240 char buf[30] ;
241 sprintf (buf, "%ld: %lu", (long) nit->first, nit->second) ;
242 output.push_front (std::string(buf)) ;
243 }
244
245 for (std::list<std::string>::const_iterator it = output.begin() ; it != output.end() ; it++) {
246 std::cout << *it << std::endl ;
247 }
248 }
249 #endif // def DEBUG
250
251 #endif // def USE_LIBJPEG
252