[834] | 1 | // |
---|
| 2 | // ******************************************************************** |
---|
| 3 | // * License and Disclaimer * |
---|
| 4 | // * * |
---|
| 5 | // * The Geant4 software is copyright of the Copyright Holders of * |
---|
| 6 | // * the Geant4 Collaboration. It is provided under the terms and * |
---|
| 7 | // * conditions of the Geant4 Software License, included in the file * |
---|
| 8 | // * LICENSE and available at http://cern.ch/geant4/license . These * |
---|
| 9 | // * include a list of copyright holders. * |
---|
| 10 | // * * |
---|
| 11 | // * Neither the authors of this software system, nor their employing * |
---|
| 12 | // * institutes,nor the agencies providing financial support for this * |
---|
| 13 | // * work make any representation or warranty, express or implied, * |
---|
| 14 | // * regarding this software system or assume any liability for its * |
---|
| 15 | // * use. Please see the license in the file LICENSE and URL above * |
---|
| 16 | // * for the full disclaimer and the limitation of liability. * |
---|
| 17 | // * * |
---|
| 18 | // * This code implementation is the result of the scientific and * |
---|
| 19 | // * technical work of the GEANT4 collaboration. * |
---|
| 20 | // * By using, copying, modifying or distributing the software (or * |
---|
| 21 | // * any work based on the software) you agree to acknowledge its * |
---|
| 22 | // * use in resulting scientific publications, and indicate your * |
---|
| 23 | // * acceptance of all terms of the Geant4 Software license. * |
---|
| 24 | // ******************************************************************** |
---|
| 25 | // |
---|
| 26 | // |
---|
| 27 | // $Id: G4RTJpegCoder.cc,v 1.6 2006/06/29 21:23:55 gunter Exp $ |
---|
[850] | 28 | // GEANT4 tag $Name: HEAD $ |
---|
[834] | 29 | // |
---|
| 30 | // |
---|
| 31 | // |
---|
| 32 | |
---|
| 33 | #include <stdlib.h> |
---|
| 34 | #include <string.h> |
---|
| 35 | #include <cmath> |
---|
| 36 | |
---|
| 37 | #include "G4RTJpeg.hh" |
---|
| 38 | #include "G4RTOutBitStream.hh" |
---|
| 39 | #include "G4RTJpegMaker.hh" |
---|
| 40 | #include "G4RTJpegCoder.hh" |
---|
| 41 | #include "G4RTJpegCoderTables.hh" |
---|
| 42 | |
---|
| 43 | |
---|
| 44 | G4JpegCoder::G4JpegCoder(u_char* colorR,u_char* colorG,u_char* colorB) |
---|
| 45 | { |
---|
| 46 | mRgb[0] = colorR; |
---|
| 47 | mRgb[1] = colorG; |
---|
| 48 | mRgb[2] = colorB; |
---|
| 49 | |
---|
| 50 | mPreDC[0] = mPreDC[1] = mPreDC[2] = 0; |
---|
| 51 | mOBSP = 0; |
---|
| 52 | |
---|
| 53 | for(int n=0; n<8; n++) |
---|
| 54 | for(int m=0; m<8; m++) |
---|
| 55 | mCosT[n][m] = std::cos((2 * m + 1) * n * PaiDiv16); |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | G4JpegCoder::~G4JpegCoder(void) |
---|
| 59 | { |
---|
| 60 | if(mOBSP != 0) |
---|
| 61 | delete mOBSP; |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | void |
---|
| 65 | G4JpegCoder::GetJpegData(char** aJpegData, int& size) |
---|
| 66 | { |
---|
| 67 | if (mOBSP != 0){ |
---|
| 68 | *aJpegData = (char*)mOBSP->GetStreamAddress(); |
---|
| 69 | size = mOBSP->GetStreamSize(); |
---|
| 70 | } |
---|
| 71 | else{ |
---|
| 72 | *aJpegData = 0; |
---|
| 73 | size = 0; |
---|
| 74 | } |
---|
| 75 | |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | int |
---|
| 79 | G4JpegCoder::DoCoding(void) |
---|
| 80 | { |
---|
| 81 | mNumVUnits = (mProperty.nRow / 16) + ((mProperty.nRow % 16) ? 1 : 0); |
---|
| 82 | mNumHUnits = (mProperty.nColumn / 16) + ((mProperty.nColumn % 16) ? 1 : 0); |
---|
| 83 | |
---|
| 84 | int size = mProperty.nColumn * mProperty.nRow * 3; |
---|
| 85 | if(size < 10240) |
---|
| 86 | size = 10240; |
---|
| 87 | |
---|
| 88 | try{ |
---|
| 89 | mOBSP = new G4OutBitStream(size); |
---|
| 90 | WriteHeader(); |
---|
| 91 | for(int yu=0; yu<mNumVUnits; yu++){ |
---|
| 92 | for(int xu=0; xu<mNumHUnits; xu++){ |
---|
| 93 | makeYCC(xu, yu); |
---|
| 94 | |
---|
| 95 | //mRgb->YCrCb |
---|
| 96 | #ifdef GRAY |
---|
| 97 | for(int i=0; i<64; i++) |
---|
| 98 | mCbBlock[i] = mCrBlock[i] = 0; |
---|
| 99 | #endif |
---|
| 100 | CodeMCU(); |
---|
| 101 | } |
---|
| 102 | } |
---|
| 103 | WriteEOI(); |
---|
| 104 | return M_NoError; |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | catch(G4MemoryError &me){ |
---|
| 108 | return M_RuntimeError; |
---|
| 109 | } |
---|
| 110 | catch(G4BufferError &be){ |
---|
| 111 | return M_RuntimeError; |
---|
| 112 | } |
---|
| 113 | catch(G4IndexError &ie){ |
---|
| 114 | return M_RuntimeError; |
---|
| 115 | } |
---|
| 116 | } |
---|
| 117 | |
---|
| 118 | //MCU |
---|
| 119 | void |
---|
| 120 | G4JpegCoder::CodeMCU(void) |
---|
| 121 | { |
---|
| 122 | for(int n=0; n<4; n++){ |
---|
| 123 | ForwardDCT(mYBlock[n]); |
---|
| 124 | Quantization(0); |
---|
| 125 | CodeHuffman(0); |
---|
| 126 | } |
---|
| 127 | ForwardDCT(mCbBlock); |
---|
| 128 | Quantization(1); |
---|
| 129 | CodeHuffman(1); |
---|
| 130 | |
---|
| 131 | ForwardDCT(mCrBlock); |
---|
| 132 | Quantization(2); |
---|
| 133 | CodeHuffman(2); |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | void |
---|
| 137 | G4JpegCoder::makeYCC(int ux, int uy) |
---|
| 138 | { |
---|
| 139 | u_char rv, gv, bv; |
---|
| 140 | int tCrBlock[4][64]; |
---|
| 141 | int tCbBlock[4][64]; |
---|
| 142 | |
---|
| 143 | for(int u=0; u<4; u++){ |
---|
| 144 | int *yp = mYBlock[u]; |
---|
| 145 | int *cbp = tCbBlock[u]; |
---|
| 146 | int *crp = tCrBlock[u]; |
---|
| 147 | |
---|
| 148 | int sx = ux * 16 + ((u&1) ? 8 : 0); |
---|
| 149 | int ex = sx + 8; |
---|
| 150 | int sy = uy * 16 + ((u>1) ? 8 : 0); |
---|
| 151 | int ey = sy + 8; |
---|
| 152 | |
---|
| 153 | for(int iv=sy; iv<ey; iv++){ |
---|
| 154 | int ii = iv < mProperty.nRow ? iv : mProperty.nRow - 1; |
---|
| 155 | for(int ih=sx; ih<ex; ih++){ |
---|
| 156 | int jj = ih < mProperty.nColumn ? ih : mProperty.nColumn - 1; |
---|
| 157 | int index = ii * mProperty.nColumn + jj; |
---|
| 158 | rv = mRgb[0][index]; |
---|
| 159 | gv = mRgb[1][index]; |
---|
| 160 | bv = mRgb[2][index]; |
---|
| 161 | |
---|
| 162 | *yp++ = int((0.2990 * rv) + (0.5870 * gv) + (0.1140 * bv) - 128) |
---|
| 163 | ; |
---|
| 164 | *cbp++ = int(-(0.1687 * rv) - (0.3313 * gv) + (0.5000 * bv)); |
---|
| 165 | *crp++ = int((0.5000 * rv) - (0.4187 * gv) - (0.0813 * bv)); |
---|
| 166 | } // ih |
---|
| 167 | } //iv |
---|
| 168 | } //u |
---|
| 169 | |
---|
| 170 | int n = 0; |
---|
| 171 | for(int b=0; b<4; b++){ |
---|
| 172 | switch(b){ |
---|
| 173 | case 0: n=0; break; |
---|
| 174 | case 1: n=4; break; |
---|
| 175 | case 2: n=32; break; |
---|
| 176 | case 3: n=36; |
---|
| 177 | } |
---|
| 178 | for(int y=0; y<8; y+=2){ |
---|
| 179 | for(int x=0; x<8; x+=2){ |
---|
| 180 | int idx = y * 8 + x; |
---|
| 181 | mCrBlock[n] = tCrBlock[b][idx]; |
---|
| 182 | mCbBlock[n] = tCbBlock[b][idx]; |
---|
| 183 | n++; |
---|
| 184 | } |
---|
| 185 | n += 4; |
---|
| 186 | } |
---|
| 187 | } |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | void |
---|
| 191 | G4JpegCoder::CodeHuffman(int cs) |
---|
| 192 | { |
---|
| 193 | const G4HuffmanCodeTable& dcT = cs ? CDcHuffmanT : YDcHuffmanT; |
---|
| 194 | const G4HuffmanCodeTable& acT = cs ? CAcHuffmanT : YAcHuffmanT; |
---|
| 195 | const int eobIdx = cs ? CEOBidx : YEOBidx; |
---|
| 196 | const int zrlIdx = cs ? CZRLidx : YZRLidx; |
---|
| 197 | |
---|
| 198 | int diff = mDCTData[0] - mPreDC[cs]; |
---|
| 199 | mPreDC[cs] = mDCTData[0]; |
---|
| 200 | int absDiff = std::abs(diff); |
---|
| 201 | int dIdx = 0; |
---|
| 202 | |
---|
| 203 | while(absDiff > 0){ |
---|
| 204 | absDiff >>= 1; |
---|
| 205 | dIdx++; |
---|
| 206 | } |
---|
| 207 | if(dIdx > dcT.numOfElement) |
---|
| 208 | throw(G4IndexError(dcT.numOfElement, dIdx, "CodeHuffman:DC")); |
---|
| 209 | mOBSP->SetBits((dcT.CodeT)[dIdx], (dcT.SizeT)[dIdx]); |
---|
| 210 | |
---|
| 211 | if(dIdx){ |
---|
| 212 | if(diff < 0) |
---|
| 213 | diff--; |
---|
| 214 | mOBSP->SetBits(diff, dIdx); |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | int run = 0; |
---|
| 218 | for(int n=1; n<64; n++){ |
---|
| 219 | int absCoefficient = std::abs( mDCTData[ Zigzag[n] ] ); |
---|
| 220 | if( absCoefficient ){ |
---|
| 221 | while( run > 15 ){ |
---|
| 222 | mOBSP->SetBits((acT.CodeT)[zrlIdx], (acT.SizeT)[zrlIdx]); |
---|
| 223 | run -= 16; |
---|
| 224 | } |
---|
| 225 | int s = 0; |
---|
| 226 | while( absCoefficient > 0 ){ |
---|
| 227 | absCoefficient >>= 1; |
---|
| 228 | s++; |
---|
| 229 | } |
---|
| 230 | int aIdx = run * 10 + s + (run == 15); |
---|
| 231 | if( aIdx >= acT.numOfElement ) |
---|
| 232 | throw( G4IndexError( acT.numOfElement, aIdx, "CodeHuffman:AC" ) |
---|
| 233 | ); |
---|
| 234 | mOBSP->SetBits( (acT.CodeT)[aIdx], (acT.SizeT)[aIdx] ); |
---|
| 235 | int v = mDCTData[ Zigzag[n] ]; |
---|
| 236 | if( v < 0 ) |
---|
| 237 | v--; |
---|
| 238 | mOBSP->SetBits( v, s ); |
---|
| 239 | run = 0; |
---|
| 240 | } |
---|
| 241 | else{ |
---|
| 242 | if(n == 63) |
---|
| 243 | mOBSP->SetBits( (acT.CodeT)[eobIdx], (acT.SizeT)[eobIdx] ); |
---|
| 244 | else |
---|
| 245 | run++; |
---|
| 246 | } |
---|
| 247 | } |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | |
---|
| 251 | void |
---|
| 252 | G4JpegCoder::Quantization(int cs) |
---|
| 253 | { |
---|
| 254 | int* qt = (int*)(cs ? CQuantumT : YQuantumT); |
---|
| 255 | for( int i=0; i<64; i++ ){ |
---|
| 256 | mDCTData[i] /= qt[i]; |
---|
| 257 | } |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | |
---|
| 261 | void |
---|
| 262 | G4JpegCoder::ForwardDCT(int* picData) |
---|
| 263 | { |
---|
| 264 | for( int v=0; v<8; v++ ){ |
---|
| 265 | double cv = v ? 1.0 : DisSqrt2; |
---|
| 266 | for( int u=0; u<8; u++ ){ |
---|
| 267 | double cu = u ? 1.0 : DisSqrt2; |
---|
| 268 | double sum = 0; |
---|
| 269 | |
---|
| 270 | for( int y=0; y<8; y++ ) |
---|
| 271 | for( int x=0; x<8; x++ ) |
---|
| 272 | sum += picData[ y * 8 + x ] * mCosT[u][x] * mCosT[v][y]; |
---|
| 273 | mDCTData[ v * 8 + u ] = int( sum * cu * cv / 4 ); |
---|
| 274 | } |
---|
| 275 | } |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | |
---|
| 279 | void |
---|
| 280 | G4JpegCoder::WriteHeader( void ) |
---|
| 281 | { |
---|
| 282 | int i = 0; //counter |
---|
| 283 | //SOI |
---|
| 284 | mOBSP->SetByte( M_Marker ); //FF |
---|
| 285 | mOBSP->SetByte( M_SOI ); //SOI |
---|
| 286 | |
---|
| 287 | //APP0(JFIF Header) |
---|
| 288 | mOBSP->SetByte( M_Marker ); //FF |
---|
| 289 | mOBSP->SetByte( M_APP0 ); //APP0 |
---|
| 290 | mOBSP->SetWord( JFIFLength ); //parameter |
---|
| 291 | mOBSP->CopyByte( (char*)JFIF, 5 ); //"JFIF\0" |
---|
| 292 | mOBSP->SetWord( JFIFVersion ); //Version |
---|
| 293 | mOBSP->SetByte( mProperty.Units ); |
---|
| 294 | mOBSP->SetWord( mProperty.HDensity ); |
---|
| 295 | mOBSP->SetWord( mProperty.VDensity ); |
---|
| 296 | mOBSP->SetByte( 0 ); |
---|
| 297 | mOBSP->SetByte( 0 ); |
---|
| 298 | |
---|
| 299 | //comment |
---|
| 300 | if( mProperty.Comment != 0 ){ |
---|
| 301 | mOBSP->SetByte( M_Marker ); //FF |
---|
| 302 | mOBSP->SetByte( M_COM ); //comment |
---|
| 303 | int length = strlen( mProperty.Comment ) + 1; |
---|
| 304 | mOBSP->SetWord( length + 2 ); |
---|
| 305 | mOBSP->CopyByte( mProperty.Comment, length ); |
---|
| 306 | } |
---|
| 307 | |
---|
| 308 | //DQT |
---|
| 309 | mOBSP->SetByte( M_Marker ); |
---|
| 310 | mOBSP->SetByte( M_DQT ); |
---|
| 311 | mOBSP->SetWord( 67 ); |
---|
| 312 | mOBSP->SetByte( 0 ); |
---|
| 313 | for( i=0; i<64; i++ ) |
---|
| 314 | mOBSP->SetByte( u_char( YQuantumT[Zigzag[i]] ) ); |
---|
| 315 | mOBSP->SetByte( M_Marker ); |
---|
| 316 | mOBSP->SetByte( M_DQT ); |
---|
| 317 | mOBSP->SetWord( 67 ); |
---|
| 318 | mOBSP->SetByte( 1 ); |
---|
| 319 | for( i=0; i<64; i++ ) |
---|
| 320 | mOBSP->SetByte( u_char( CQuantumT[Zigzag[i]] ) ); |
---|
| 321 | // DHT |
---|
| 322 | mOBSP->CopyByte( (char*)YDcDht, DcDhtLength ); |
---|
| 323 | mOBSP->CopyByte( (char*)CDcDht, DcDhtLength ); |
---|
| 324 | mOBSP->CopyByte( (char*)YAcDht, AcDhtLength ); |
---|
| 325 | mOBSP->CopyByte( (char*)CAcDht, AcDhtLength ); |
---|
| 326 | |
---|
| 327 | // Frame Header |
---|
| 328 | mOBSP->SetByte( M_Marker ); // FF |
---|
| 329 | mOBSP->SetByte( M_SOF0 ); |
---|
| 330 | mOBSP->SetWord( 3 * mProperty.Dimension + 8 ); |
---|
| 331 | mOBSP->SetByte( mProperty.SamplePrecision ); |
---|
| 332 | mOBSP->SetWord( mProperty.nRow ); |
---|
| 333 | mOBSP->SetWord( mProperty.nColumn ); |
---|
| 334 | mOBSP->SetByte( mProperty.Dimension ); |
---|
| 335 | |
---|
| 336 | mOBSP->SetByte( 0 ); |
---|
| 337 | mOBSP->SetByte( YSampleF ); |
---|
| 338 | mOBSP->SetByte( 0 ); |
---|
| 339 | |
---|
| 340 | mOBSP->SetByte( 1 ); |
---|
| 341 | mOBSP->SetByte( CSampleF ); |
---|
| 342 | |
---|
| 343 | mOBSP->SetByte( 1 ); |
---|
| 344 | mOBSP->SetByte( 2 ); |
---|
| 345 | mOBSP->SetByte( CSampleF ); |
---|
| 346 | mOBSP->SetByte( 1 ); |
---|
| 347 | |
---|
| 348 | //Scan Header |
---|
| 349 | mOBSP->SetByte( M_Marker ); |
---|
| 350 | mOBSP->SetByte( M_SOS ); |
---|
| 351 | mOBSP->SetWord( 2 * mProperty.Dimension + 6 ); |
---|
| 352 | mOBSP->SetByte( mProperty.Dimension ); |
---|
| 353 | for( i=0; i<mProperty.Dimension; i++ ){ |
---|
| 354 | mOBSP->SetByte( i ); |
---|
| 355 | mOBSP->SetByte( i==0 ? 0 : 0x11 ); |
---|
| 356 | } |
---|
| 357 | mOBSP->SetByte( 0 ); //Ss |
---|
| 358 | mOBSP->SetByte( 63 ); //Se |
---|
| 359 | mOBSP->SetByte( 0 ); //Ah,Al |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | //EOI |
---|
| 363 | void |
---|
| 364 | G4JpegCoder::WriteEOI( void ) |
---|
| 365 | { |
---|
| 366 | mOBSP->SetByte( M_Marker ); |
---|
| 367 | mOBSP->SetByte( M_EOI ); |
---|
| 368 | } |
---|
| 369 | |
---|
| 370 | //SetJpegProperty |
---|
| 371 | void |
---|
| 372 | G4JpegCoder::SetJpegProperty(const G4JpegProperty& aProperty ) |
---|
| 373 | { |
---|
| 374 | mProperty = aProperty; |
---|
| 375 | mProperty.Dimension = 3; |
---|
| 376 | mProperty.SamplePrecision = 8; |
---|
| 377 | mProperty.Format = 1; |
---|
| 378 | mProperty.MajorRevisions = 1; |
---|
| 379 | mProperty.MinorRevisions = 2; |
---|
| 380 | mProperty.HThumbnail = 0; |
---|
| 381 | mProperty.VThumbnail = 0; |
---|
| 382 | } |
---|