< prev index next >

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

Print this page




 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) {


 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.




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


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


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


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


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


< prev index next >