< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java

Print this page


   1 /*
   2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 177         java.security.AccessController.doPrivileged(
 178             new java.security.PrivilegedAction<Void>() {
 179                 public Void run() {
 180                     System.loadLibrary("javajpeg");
 181                     return null;
 182                 }
 183             });
 184         initWriterIDs(JPEGQTable.class,
 185                       JPEGHuffmanTable.class);
 186     }
 187 
 188     //////// Public API
 189 
 190     public JPEGImageWriter(ImageWriterSpi originator) {
 191         super(originator);
 192         structPointer = initJPEGImageWriter();
 193         disposerRecord = new JPEGWriterDisposerRecord(structPointer);
 194         Disposer.addRecord(disposerReferent, disposerRecord);
 195     }
 196 

 197     public void setOutput(Object output) {
 198         setThreadLock();
 199         try {
 200             cbLock.check();
 201 
 202             super.setOutput(output); // validates output
 203             resetInternalState();
 204             ios = (ImageOutputStream) output; // so this will always work
 205             // Set the native destination
 206             setDest(structPointer);
 207         } finally {
 208             clearThreadLock();
 209         }
 210     }
 211 

 212     public ImageWriteParam getDefaultWriteParam() {
 213         return new JPEGImageWriteParam(null);
 214     }
 215 

 216     public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
 217         setThreadLock();
 218         try {
 219             return new JPEGMetadata(param, this);
 220         } finally {
 221             clearThreadLock();
 222         }
 223     }
 224 

 225     public IIOMetadata
 226         getDefaultImageMetadata(ImageTypeSpecifier imageType,
 227                                 ImageWriteParam param) {
 228         setThreadLock();
 229         try {
 230             return new JPEGMetadata(imageType, param, this);
 231         } finally {
 232             clearThreadLock();
 233         }
 234     }
 235 

 236     public IIOMetadata convertStreamMetadata(IIOMetadata inData,
 237                                              ImageWriteParam param) {
 238         // There isn't much we can do.  If it's one of ours, then
 239         // return it.  Otherwise just return null.  We use it only
 240         // for tables, so we can't get a default and modify it,
 241         // as this will usually not be what is intended.
 242         if (inData instanceof JPEGMetadata) {
 243             JPEGMetadata jpegData = (JPEGMetadata) inData;
 244             if (jpegData.isStream) {
 245                 return inData;
 246             }
 247         }
 248         return null;
 249     }
 250 

 251     public IIOMetadata
 252         convertImageMetadata(IIOMetadata inData,
 253                              ImageTypeSpecifier imageType,
 254                              ImageWriteParam param) {
 255         setThreadLock();
 256         try {
 257             return convertImageMetadataOnThread(inData, imageType, param);
 258         } finally {
 259             clearThreadLock();
 260         }
 261     }
 262 
 263     private IIOMetadata
 264         convertImageMetadataOnThread(IIOMetadata inData,
 265                                      ImageTypeSpecifier imageType,
 266                                      ImageWriteParam param) {
 267         // If it's one of ours, just return it
 268         if (inData instanceof JPEGMetadata) {
 269             JPEGMetadata jpegData = (JPEGMetadata) inData;
 270             if (!jpegData.isStream) {


 282                 IIOMetadataFormatImpl.standardMetadataFormatName;
 283             Node tree = inData.getAsTree(formatName);
 284             if (tree != null) {
 285                 JPEGMetadata jpegData = new JPEGMetadata(imageType,
 286                                                          param,
 287                                                          this);
 288                 try {
 289                     jpegData.setFromTree(formatName, tree);
 290                 } catch (IIOInvalidTreeException e) {
 291                     // Other plug-in generates bogus standard tree
 292                     // XXX Maybe this should put out a warning?
 293                     return null;
 294                 }
 295 
 296                 return jpegData;
 297             }
 298         }
 299         return null;
 300     }
 301 

 302     public int getNumThumbnailsSupported(ImageTypeSpecifier imageType,
 303                                          ImageWriteParam param,
 304                                          IIOMetadata streamMetadata,
 305                                          IIOMetadata imageMetadata) {
 306         // Check whether sufficient data is available.
 307         if (imageType == null && imageMetadata == null) {
 308             // The method has been invoked with insufficient data. Henceforth
 309             // we return -1 as recommended by ImageWriter specification.
 310             return -1;
 311         }
 312 
 313         // Check if the image type and metadata are JFIF compatible.
 314         if (jfifOK(imageType, param, streamMetadata, imageMetadata)) {
 315             return Integer.MAX_VALUE;
 316         }
 317         return 0;
 318     }
 319 
 320     static final Dimension [] preferredThumbSizes = {new Dimension(1, 1),
 321                                                      new Dimension(255, 255)};
 322 
 323     public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType,
 324                                                   ImageWriteParam param,
 325                                                   IIOMetadata streamMetadata,
 326                                                   IIOMetadata imageMetadata) {
 327         if (jfifOK(imageType, param, streamMetadata, imageMetadata)) {
 328             return preferredThumbSizes.clone();
 329         }
 330         return null;
 331     }
 332 
 333     private boolean jfifOK(ImageTypeSpecifier imageType,
 334                            ImageWriteParam param,
 335                            IIOMetadata streamMetadata,
 336                            IIOMetadata imageMetadata) {
 337         // If the image type and metadata are JFIF compatible, return true
 338         if ((imageType != null) &&
 339             (!JPEG.isJFIFcompliant(imageType, true))) {
 340             return false;
 341         }
 342         if (imageMetadata != null) {
 343             JPEGMetadata metadata = null;
 344             if (imageMetadata instanceof JPEGMetadata) {
 345                 metadata = (JPEGMetadata) imageMetadata;
 346             } else {
 347                 metadata = (JPEGMetadata)convertImageMetadata(imageMetadata,
 348                                                               imageType,
 349                                                               param);
 350             }
 351             // metadata must have a jfif node
 352             if (metadata.findMarkerSegment
 353                 (JFIFMarkerSegment.class, true) == null){
 354                 return false;
 355             }
 356         }
 357         return true;
 358     }
 359 

 360     public boolean canWriteRasters() {
 361         return true;
 362     }
 363 

 364     public void write(IIOMetadata streamMetadata,
 365                       IIOImage image,
 366                       ImageWriteParam param) throws IOException {
 367         setThreadLock();
 368         try {
 369             cbLock.check();
 370 
 371             writeOnThread(streamMetadata, image, param);
 372         } finally {
 373             clearThreadLock();
 374         }
 375     }
 376 
 377     private void writeOnThread(IIOMetadata streamMetadata,
 378                       IIOImage image,
 379                       ImageWriteParam param) throws IOException {
 380 
 381         if (ios == null) {
 382             throw new IllegalStateException("Output has not been set!");
 383         }


1032         cbLock.lock();
1033         try {
1034             if (aborted) {
1035                 processWriteAborted();
1036             } else {
1037                 processImageComplete();
1038             }
1039 
1040             ios.flush();
1041         } finally {
1042             cbLock.unlock();
1043         }
1044         currentImage++;  // After a successful write
1045     }
1046 
1047     @Override
1048     public boolean canWriteSequence() {
1049         return true;
1050     }
1051 

1052     public void prepareWriteSequence(IIOMetadata streamMetadata)
1053         throws IOException {
1054         setThreadLock();
1055         try {
1056             cbLock.check();
1057 
1058             prepareWriteSequenceOnThread(streamMetadata);
1059         } finally {
1060             clearThreadLock();
1061         }
1062     }
1063 
1064     private void prepareWriteSequenceOnThread(IIOMetadata streamMetadata)
1065         throws IOException {
1066         if (ios == null) {
1067             throw new IllegalStateException("Output has not been set!");
1068         }
1069 
1070         /*
1071          * from jpeg_metadata.html:


1113                     streamDCHuffmanTables = JPEG.getDefaultHuffmanTables(true);
1114                 }
1115                 streamACHuffmanTables =
1116                     collectHTablesFromMetadata(jmeta, false);
1117                 if (streamACHuffmanTables == null) {
1118                     streamACHuffmanTables = JPEG.getDefaultHuffmanTables(false);
1119                 }
1120 
1121                 // Now write them out
1122                 writeTables(structPointer,
1123                             streamQTables,
1124                             streamDCHuffmanTables,
1125                             streamACHuffmanTables);
1126             } else {
1127                 throw new IIOException("Stream metadata must be JPEG metadata");
1128             }
1129         }
1130         sequencePrepared = true;
1131     }
1132 

1133     public void writeToSequence(IIOImage image, ImageWriteParam param)
1134         throws IOException {
1135         setThreadLock();
1136         try {
1137             cbLock.check();
1138 
1139             if (sequencePrepared == false) {
1140                 throw new IllegalStateException("sequencePrepared not called!");
1141             }
1142             // In the case of JPEG this does nothing different from write
1143             write(null, image, param);
1144         } finally {
1145             clearThreadLock();
1146         }
1147     }
1148 

1149     public void endWriteSequence() throws IOException {
1150         setThreadLock();
1151         try {
1152             cbLock.check();
1153 
1154             if (sequencePrepared == false) {
1155                 throw new IllegalStateException("sequencePrepared not called!");
1156             }
1157             sequencePrepared = false;
1158         } finally {
1159             clearThreadLock();
1160         }
1161     }
1162 

1163     public synchronized void abort() {
1164         setThreadLock();
1165         try {
1166             /**
1167              * NB: we do not check the call back lock here, we allow to abort
1168              * the reader any time.
1169              */
1170             super.abort();
1171             abortWrite(structPointer);
1172         } finally {
1173             clearThreadLock();
1174         }
1175     }
1176 
1177     @Override
1178     protected synchronized void clearAbortRequest() {
1179         setThreadLock();
1180         try {
1181             cbLock.check();
1182             if (abortRequested()) {


1187                 setDest(structPointer);
1188             }
1189         } finally {
1190             clearThreadLock();
1191         }
1192     }
1193 
1194     private void resetInternalState() {
1195         // reset C structures
1196         resetWriter(structPointer);
1197 
1198         // reset local Java structures
1199         srcRas = null;
1200         raster = null;
1201         convertTosRGB = false;
1202         currentImage = 0;
1203         numScans = 0;
1204         metadata = null;
1205     }
1206 

1207     public void reset() {
1208         setThreadLock();
1209         try {
1210             cbLock.check();
1211 
1212             super.reset();
1213         } finally {
1214             clearThreadLock();
1215         }
1216     }
1217 

1218     public void dispose() {
1219         setThreadLock();
1220         try {
1221             cbLock.check();
1222 
1223             if (structPointer != 0) {
1224                 disposerRecord.dispose();
1225                 structPointer = 0;
1226             }
1227         } finally {
1228             clearThreadLock();
1229         }
1230     }
1231 
1232     ////////// End of public API
1233 
1234     ///////// Package-access API
1235 
1236     /**
1237      * Called by the native code or other classes to signal a warning.


1718             }
1719         }
1720     }
1721 
1722     /** Aborts the current write in the native code */
1723     private native void abortWrite(long structPointer);
1724 
1725     /** Resets native structures */
1726     private native void resetWriter(long structPointer);
1727 
1728     /** Releases native structures */
1729     private static native void disposeWriter(long structPointer);
1730 
1731     private static class JPEGWriterDisposerRecord implements DisposerRecord {
1732         private long pData;
1733 
1734         public JPEGWriterDisposerRecord(long pData) {
1735             this.pData = pData;
1736         }
1737 

1738         public synchronized void dispose() {
1739             if (pData != 0) {
1740                 disposeWriter(pData);
1741                 pData = 0;
1742             }
1743         }
1744     }
1745 
1746     /**
1747      * This method is called from native code in order to write encoder
1748      * output to the destination.
1749      *
1750      * We block any attempt to change the writer state during this
1751      * method, in order to prevent a corruption of the native encoder
1752      * state.
1753      */
1754     private void writeOutputData(byte[] data, int offset, int len)
1755             throws IOException
1756     {
1757         cbLock.lock();


   1 /*
   2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 177         java.security.AccessController.doPrivileged(
 178             new java.security.PrivilegedAction<Void>() {
 179                 public Void run() {
 180                     System.loadLibrary("javajpeg");
 181                     return null;
 182                 }
 183             });
 184         initWriterIDs(JPEGQTable.class,
 185                       JPEGHuffmanTable.class);
 186     }
 187 
 188     //////// Public API
 189 
 190     public JPEGImageWriter(ImageWriterSpi originator) {
 191         super(originator);
 192         structPointer = initJPEGImageWriter();
 193         disposerRecord = new JPEGWriterDisposerRecord(structPointer);
 194         Disposer.addRecord(disposerReferent, disposerRecord);
 195     }
 196 
 197     @Override
 198     public void setOutput(Object output) {
 199         setThreadLock();
 200         try {
 201             cbLock.check();
 202 
 203             super.setOutput(output); // validates output
 204             resetInternalState();
 205             ios = (ImageOutputStream) output; // so this will always work
 206             // Set the native destination
 207             setDest(structPointer);
 208         } finally {
 209             clearThreadLock();
 210         }
 211     }
 212 
 213     @Override
 214     public ImageWriteParam getDefaultWriteParam() {
 215         return new JPEGImageWriteParam(null);
 216     }
 217 
 218     @Override
 219     public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
 220         setThreadLock();
 221         try {
 222             return new JPEGMetadata(param, this);
 223         } finally {
 224             clearThreadLock();
 225         }
 226     }
 227 
 228     @Override
 229     public IIOMetadata
 230         getDefaultImageMetadata(ImageTypeSpecifier imageType,
 231                                 ImageWriteParam param) {
 232         setThreadLock();
 233         try {
 234             return new JPEGMetadata(imageType, param, this);
 235         } finally {
 236             clearThreadLock();
 237         }
 238     }
 239 
 240     @Override
 241     public IIOMetadata convertStreamMetadata(IIOMetadata inData,
 242                                              ImageWriteParam param) {
 243         // There isn't much we can do.  If it's one of ours, then
 244         // return it.  Otherwise just return null.  We use it only
 245         // for tables, so we can't get a default and modify it,
 246         // as this will usually not be what is intended.
 247         if (inData instanceof JPEGMetadata) {
 248             JPEGMetadata jpegData = (JPEGMetadata) inData;
 249             if (jpegData.isStream) {
 250                 return inData;
 251             }
 252         }
 253         return null;
 254     }
 255 
 256     @Override
 257     public IIOMetadata
 258         convertImageMetadata(IIOMetadata inData,
 259                              ImageTypeSpecifier imageType,
 260                              ImageWriteParam param) {
 261         setThreadLock();
 262         try {
 263             return convertImageMetadataOnThread(inData, imageType, param);
 264         } finally {
 265             clearThreadLock();
 266         }
 267     }
 268 
 269     private IIOMetadata
 270         convertImageMetadataOnThread(IIOMetadata inData,
 271                                      ImageTypeSpecifier imageType,
 272                                      ImageWriteParam param) {
 273         // If it's one of ours, just return it
 274         if (inData instanceof JPEGMetadata) {
 275             JPEGMetadata jpegData = (JPEGMetadata) inData;
 276             if (!jpegData.isStream) {


 288                 IIOMetadataFormatImpl.standardMetadataFormatName;
 289             Node tree = inData.getAsTree(formatName);
 290             if (tree != null) {
 291                 JPEGMetadata jpegData = new JPEGMetadata(imageType,
 292                                                          param,
 293                                                          this);
 294                 try {
 295                     jpegData.setFromTree(formatName, tree);
 296                 } catch (IIOInvalidTreeException e) {
 297                     // Other plug-in generates bogus standard tree
 298                     // XXX Maybe this should put out a warning?
 299                     return null;
 300                 }
 301 
 302                 return jpegData;
 303             }
 304         }
 305         return null;
 306     }
 307 
 308     @Override
 309     public int getNumThumbnailsSupported(ImageTypeSpecifier imageType,
 310                                          ImageWriteParam param,
 311                                          IIOMetadata streamMetadata,
 312                                          IIOMetadata imageMetadata) {
 313         // Check whether sufficient data is available.
 314         if (imageType == null && imageMetadata == null) {
 315             // The method has been invoked with insufficient data. Henceforth
 316             // we return -1 as recommended by ImageWriter specification.
 317             return -1;
 318         }
 319 
 320         // Check if the image type and metadata are JFIF compatible.
 321         if (jfifOK(imageType, param, streamMetadata, imageMetadata)) {
 322             return Integer.MAX_VALUE;
 323         }
 324         return 0;
 325     }
 326 
 327     static final Dimension [] preferredThumbSizes = {new Dimension(1, 1),
 328                                                      new Dimension(255, 255)};
 329     @Override
 330     public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType,
 331                                                   ImageWriteParam param,
 332                                                   IIOMetadata streamMetadata,
 333                                                   IIOMetadata imageMetadata) {
 334         if (jfifOK(imageType, param, streamMetadata, imageMetadata)) {
 335             return preferredThumbSizes.clone();
 336         }
 337         return null;
 338     }
 339 
 340     private boolean jfifOK(ImageTypeSpecifier imageType,
 341                            ImageWriteParam param,
 342                            IIOMetadata streamMetadata,
 343                            IIOMetadata imageMetadata) {
 344         // If the image type and metadata are JFIF compatible, return true
 345         if ((imageType != null) &&
 346             (!JPEG.isJFIFcompliant(imageType, true))) {
 347             return false;
 348         }
 349         if (imageMetadata != null) {
 350             JPEGMetadata metadata = null;
 351             if (imageMetadata instanceof JPEGMetadata) {
 352                 metadata = (JPEGMetadata) imageMetadata;
 353             } else {
 354                 metadata = (JPEGMetadata)convertImageMetadata(imageMetadata,
 355                                                               imageType,
 356                                                               param);
 357             }
 358             // metadata must have a jfif node
 359             if (metadata.findMarkerSegment
 360                 (JFIFMarkerSegment.class, true) == null){
 361                 return false;
 362             }
 363         }
 364         return true;
 365     }
 366 
 367     @Override
 368     public boolean canWriteRasters() {
 369         return true;
 370     }
 371 
 372     @Override
 373     public void write(IIOMetadata streamMetadata,
 374                       IIOImage image,
 375                       ImageWriteParam param) throws IOException {
 376         setThreadLock();
 377         try {
 378             cbLock.check();
 379 
 380             writeOnThread(streamMetadata, image, param);
 381         } finally {
 382             clearThreadLock();
 383         }
 384     }
 385 
 386     private void writeOnThread(IIOMetadata streamMetadata,
 387                       IIOImage image,
 388                       ImageWriteParam param) throws IOException {
 389 
 390         if (ios == null) {
 391             throw new IllegalStateException("Output has not been set!");
 392         }


1041         cbLock.lock();
1042         try {
1043             if (aborted) {
1044                 processWriteAborted();
1045             } else {
1046                 processImageComplete();
1047             }
1048 
1049             ios.flush();
1050         } finally {
1051             cbLock.unlock();
1052         }
1053         currentImage++;  // After a successful write
1054     }
1055 
1056     @Override
1057     public boolean canWriteSequence() {
1058         return true;
1059     }
1060 
1061     @Override
1062     public void prepareWriteSequence(IIOMetadata streamMetadata)
1063         throws IOException {
1064         setThreadLock();
1065         try {
1066             cbLock.check();
1067 
1068             prepareWriteSequenceOnThread(streamMetadata);
1069         } finally {
1070             clearThreadLock();
1071         }
1072     }
1073 
1074     private void prepareWriteSequenceOnThread(IIOMetadata streamMetadata)
1075         throws IOException {
1076         if (ios == null) {
1077             throw new IllegalStateException("Output has not been set!");
1078         }
1079 
1080         /*
1081          * from jpeg_metadata.html:


1123                     streamDCHuffmanTables = JPEG.getDefaultHuffmanTables(true);
1124                 }
1125                 streamACHuffmanTables =
1126                     collectHTablesFromMetadata(jmeta, false);
1127                 if (streamACHuffmanTables == null) {
1128                     streamACHuffmanTables = JPEG.getDefaultHuffmanTables(false);
1129                 }
1130 
1131                 // Now write them out
1132                 writeTables(structPointer,
1133                             streamQTables,
1134                             streamDCHuffmanTables,
1135                             streamACHuffmanTables);
1136             } else {
1137                 throw new IIOException("Stream metadata must be JPEG metadata");
1138             }
1139         }
1140         sequencePrepared = true;
1141     }
1142 
1143     @Override
1144     public void writeToSequence(IIOImage image, ImageWriteParam param)
1145         throws IOException {
1146         setThreadLock();
1147         try {
1148             cbLock.check();
1149 
1150             if (sequencePrepared == false) {
1151                 throw new IllegalStateException("sequencePrepared not called!");
1152             }
1153             // In the case of JPEG this does nothing different from write
1154             write(null, image, param);
1155         } finally {
1156             clearThreadLock();
1157         }
1158     }
1159 
1160     @Override
1161     public void endWriteSequence() throws IOException {
1162         setThreadLock();
1163         try {
1164             cbLock.check();
1165 
1166             if (sequencePrepared == false) {
1167                 throw new IllegalStateException("sequencePrepared not called!");
1168             }
1169             sequencePrepared = false;
1170         } finally {
1171             clearThreadLock();
1172         }
1173     }
1174 
1175     @Override
1176     public synchronized void abort() {
1177         setThreadLock();
1178         try {
1179             /**
1180              * NB: we do not check the call back lock here, we allow to abort
1181              * the reader any time.
1182              */
1183             super.abort();
1184             abortWrite(structPointer);
1185         } finally {
1186             clearThreadLock();
1187         }
1188     }
1189 
1190     @Override
1191     protected synchronized void clearAbortRequest() {
1192         setThreadLock();
1193         try {
1194             cbLock.check();
1195             if (abortRequested()) {


1200                 setDest(structPointer);
1201             }
1202         } finally {
1203             clearThreadLock();
1204         }
1205     }
1206 
1207     private void resetInternalState() {
1208         // reset C structures
1209         resetWriter(structPointer);
1210 
1211         // reset local Java structures
1212         srcRas = null;
1213         raster = null;
1214         convertTosRGB = false;
1215         currentImage = 0;
1216         numScans = 0;
1217         metadata = null;
1218     }
1219 
1220     @Override
1221     public void reset() {
1222         setThreadLock();
1223         try {
1224             cbLock.check();
1225 
1226             super.reset();
1227         } finally {
1228             clearThreadLock();
1229         }
1230     }
1231 
1232     @Override
1233     public void dispose() {
1234         setThreadLock();
1235         try {
1236             cbLock.check();
1237 
1238             if (structPointer != 0) {
1239                 disposerRecord.dispose();
1240                 structPointer = 0;
1241             }
1242         } finally {
1243             clearThreadLock();
1244         }
1245     }
1246 
1247     ////////// End of public API
1248 
1249     ///////// Package-access API
1250 
1251     /**
1252      * Called by the native code or other classes to signal a warning.


1733             }
1734         }
1735     }
1736 
1737     /** Aborts the current write in the native code */
1738     private native void abortWrite(long structPointer);
1739 
1740     /** Resets native structures */
1741     private native void resetWriter(long structPointer);
1742 
1743     /** Releases native structures */
1744     private static native void disposeWriter(long structPointer);
1745 
1746     private static class JPEGWriterDisposerRecord implements DisposerRecord {
1747         private long pData;
1748 
1749         public JPEGWriterDisposerRecord(long pData) {
1750             this.pData = pData;
1751         }
1752 
1753         @Override
1754         public synchronized void dispose() {
1755             if (pData != 0) {
1756                 disposeWriter(pData);
1757                 pData = 0;
1758             }
1759         }
1760     }
1761 
1762     /**
1763      * This method is called from native code in order to write encoder
1764      * output to the destination.
1765      *
1766      * We block any attempt to change the writer state during this
1767      * method, in order to prevent a corruption of the native encoder
1768      * state.
1769      */
1770     private void writeOutputData(byte[] data, int offset, int len)
1771             throws IOException
1772     {
1773         cbLock.lock();


< prev index next >