< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java

Print this page


   1 /*
   2  * Copyright (c) 2005, 2014, 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


 557      * @param sm The stream metadata or {@code null} if
 558      * {@code writeHeader} is {@code false}.
 559      * @param iioimage The image and image metadata.
 560      * @param p The write parameters.
 561      *
 562      * @throws IllegalArgumentException if the number of bands is not 1.
 563      * @throws IllegalArgumentException if the number of bits per sample is
 564      * greater than 8.
 565      * @throws IllegalArgumentException if the color component size is
 566      * greater than 8.
 567      * @throws IllegalArgumentException if {@code writeHeader} is
 568      * {@code true} and {@code sm} is {@code null}.
 569      * @throws IllegalArgumentException if {@code writeHeader} is
 570      * {@code false} and a sequence is not being written.
 571      */
 572     private void write(boolean writeHeader,
 573                        boolean writeTrailer,
 574                        IIOMetadata sm,
 575                        IIOImage iioimage,
 576                        ImageWriteParam p) throws IOException {
 577         clearAbortRequest();
 578 
 579         RenderedImage image = iioimage.getRenderedImage();
 580 
 581         // Check for ability to encode image.
 582         if (needToCreateIndex(image)) {
 583             image = PaletteBuilder.createIndexedImage(image);
 584             iioimage.setRenderedImage(image);
 585         }
 586 
 587         ColorModel colorModel = image.getColorModel();
 588         SampleModel sampleModel = image.getSampleModel();
 589 
 590         // Determine source region and destination dimensions.
 591         Rectangle sourceBounds = new Rectangle(image.getMinX(),
 592                                                image.getMinY(),
 593                                                image.getWidth(),
 594                                                image.getHeight());
 595         Dimension destSize = new Dimension();
 596         computeRegions(sourceBounds, destSize, p);
 597 


 812         // Write image data
 813         writeRasterData(image, sourceBounds, destSize,
 814                         param, imageMetadata.interlaceFlag);
 815     }
 816 
 817     private void writeRows(RenderedImage image, LZWCompressor compressor,
 818                            int sx, int sdx, int sy, int sdy, int sw,
 819                            int dy, int ddy, int dw, int dh,
 820                            int numRowsWritten, int progressReportRowPeriod)
 821       throws IOException {
 822         if (DEBUG) System.out.println("Writing unoptimized");
 823 
 824         int[] sbuf = new int[sw];
 825         byte[] dbuf = new byte[dw];
 826 
 827         Raster raster =
 828             image.getNumXTiles() == 1 && image.getNumYTiles() == 1 ?
 829             image.getTile(0, 0) : image.getData();
 830         for (int y = dy; y < dh; y += ddy) {
 831             if (numRowsWritten % progressReportRowPeriod == 0) {

 832                 if (abortRequested()) {
 833                     processWriteAborted();
 834                     return;
 835                 }
 836                 processImageProgress((numRowsWritten*100.0F)/dh);
 837             }
 838 
 839             raster.getSamples(sx, sy, sw, 1, 0, sbuf);
 840             for (int i = 0, j = 0; i < dw; i++, j += sdx) {
 841                 dbuf[i] = (byte)sbuf[j];
 842             }
 843             compressor.compress(dbuf, 0, dw);
 844             numRowsWritten++;
 845             sy += sdy;
 846         }
 847     }
 848 
 849     private void writeRowsOpt(byte[] data, int offset, int lineStride,
 850                               LZWCompressor compressor,
 851                               int dy, int ddy, int dw, int dh,
 852                               int numRowsWritten, int progressReportRowPeriod)
 853       throws IOException {
 854         if (DEBUG) System.out.println("Writing optimized");
 855 
 856         offset += dy*lineStride;
 857         lineStride *= ddy;
 858         for (int y = dy; y < dh; y += ddy) {
 859             if (numRowsWritten % progressReportRowPeriod == 0) {

 860                 if (abortRequested()) {
 861                     processWriteAborted();
 862                     return;
 863                 }
 864                 processImageProgress((numRowsWritten*100.0F)/dh);
 865             }
 866 
 867             compressor.compress(data, offset, dw);
 868             numRowsWritten++;
 869             offset += lineStride;
 870         }
 871     }
 872 
 873     private void writeRasterData(RenderedImage image,
 874                                  Rectangle sourceBounds,
 875                                  Dimension destSize,
 876                                  ImageWriteParam param,
 877                                  boolean interlaceFlag) throws IOException {
 878 
 879         int sourceXOffset = sourceBounds.x;
 880         int sourceYOffset = sourceBounds.y;
 881         int sourceWidth = sourceBounds.width;
 882         int sourceHeight = sourceBounds.height;
 883 
 884         int destWidth = destSize.width;


 907             new LZWCompressor(stream, initCodeSize, false);
 908 
 909         /* At this moment we know that input image is indexed image.
 910          * We can directly copy data iff:
 911          *   - no subsampling required (periodX = 1, periodY = 0)
 912          *   - we can access data directly (image is non-tiled,
 913          *     i.e. image data are in single block)
 914          *   - we can calculate offset in data buffer (next 3 lines)
 915          */
 916         boolean isOptimizedCase =
 917             periodX == 1 && periodY == 1 &&
 918             image.getNumXTiles() == 1 && image.getNumYTiles() == 1 &&
 919             sampleModel instanceof ComponentSampleModel &&
 920             image.getTile(0, 0) instanceof ByteComponentRaster &&
 921             image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte;
 922 
 923         int numRowsWritten = 0;
 924 
 925         int progressReportRowPeriod = Math.max(destHeight/20, 1);
 926 

 927         processImageStarted(imageIndex);




 928 
 929         if (interlaceFlag) {
 930             if (DEBUG) System.out.println("Writing interlaced");
 931 
 932             if (isOptimizedCase) {
 933                 ByteComponentRaster tile =
 934                     (ByteComponentRaster)image.getTile(0, 0);
 935                 byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData();
 936                 ComponentSampleModel csm =
 937                     (ComponentSampleModel)tile.getSampleModel();
 938                 int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0);
 939                 // take into account the raster data offset
 940                 offset += tile.getDataOffset(0);
 941                 int lineStride = csm.getScanlineStride();
 942 
 943                 writeRowsOpt(data, offset, lineStride, compressor,
 944                              0, 8, destWidth, destHeight,
 945                              numRowsWritten, progressReportRowPeriod);
 946 
 947                 if (abortRequested()) {


 956 
 957                 if (abortRequested()) {
 958                     return;
 959                 }
 960 
 961                 numRowsWritten += (destHeight - 4)/8;
 962 
 963                 writeRowsOpt(data, offset, lineStride, compressor,
 964                              2, 4, destWidth, destHeight,
 965                              numRowsWritten, progressReportRowPeriod);
 966 
 967                 if (abortRequested()) {
 968                     return;
 969                 }
 970 
 971                 numRowsWritten += (destHeight - 2)/4;
 972 
 973                 writeRowsOpt(data, offset, lineStride, compressor,
 974                              1, 2, destWidth, destHeight,
 975                              numRowsWritten, progressReportRowPeriod);



 976             } else {
 977                 writeRows(image, compressor,
 978                           sourceXOffset, periodX,
 979                           sourceYOffset, 8*periodY,
 980                           sourceWidth,
 981                           0, 8, destWidth, destHeight,
 982                           numRowsWritten, progressReportRowPeriod);
 983 
 984                 if (abortRequested()) {
 985                     return;
 986                 }
 987 
 988                 numRowsWritten += destHeight/8;
 989 
 990                 writeRows(image, compressor, sourceXOffset, periodX,
 991                           sourceYOffset + 4*periodY, 8*periodY,
 992                           sourceWidth,
 993                           4, 8, destWidth, destHeight,
 994                           numRowsWritten, progressReportRowPeriod);
 995 


 999 
1000                 numRowsWritten += (destHeight - 4)/8;
1001 
1002                 writeRows(image, compressor, sourceXOffset, periodX,
1003                           sourceYOffset + 2*periodY, 4*periodY,
1004                           sourceWidth,
1005                           2, 4, destWidth, destHeight,
1006                           numRowsWritten, progressReportRowPeriod);
1007 
1008                 if (abortRequested()) {
1009                     return;
1010                 }
1011 
1012                 numRowsWritten += (destHeight - 2)/4;
1013 
1014                 writeRows(image, compressor, sourceXOffset, periodX,
1015                           sourceYOffset + periodY, 2*periodY,
1016                           sourceWidth,
1017                           1, 2, destWidth, destHeight,
1018                           numRowsWritten, progressReportRowPeriod);



1019             }
1020         } else {
1021             if (DEBUG) System.out.println("Writing non-interlaced");
1022 
1023             if (isOptimizedCase) {
1024                 Raster tile = image.getTile(0, 0);
1025                 byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData();
1026                 ComponentSampleModel csm =
1027                     (ComponentSampleModel)tile.getSampleModel();
1028                 int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0);
1029                 int lineStride = csm.getScanlineStride();
1030 
1031                 writeRowsOpt(data, offset, lineStride, compressor,
1032                              0, 1, destWidth, destHeight,
1033                              numRowsWritten, progressReportRowPeriod);



1034             } else {
1035                 writeRows(image, compressor,
1036                           sourceXOffset, periodX,
1037                           sourceYOffset, periodY,
1038                           sourceWidth,
1039                           0, 1, destWidth, destHeight,
1040                           numRowsWritten, progressReportRowPeriod);
1041             }
1042         }
1043 
1044         if (abortRequested()) {
1045             return;
1046         }
1047 
1048         processImageProgress(100.0F);
1049 
1050         compressor.flush();
1051 
1052         stream.write(0x00);
1053 
1054         processImageComplete();
1055     }
1056 
1057     private void writeHeader(String version,
1058                              int logicalScreenWidth,
1059                              int logicalScreenHeight,
1060                              int colorResolution,
1061                              int pixelAspectRatio,
1062                              int backgroundColorIndex,
1063                              boolean sortFlag,
1064                              int bitsPerPixel,
1065                              byte[] globalColorTable) throws IOException {
1066         try {
1067             // Signature
1068             stream.writeBytes("GIF"+version);


   1 /*
   2  * Copyright (c) 2005, 2016, 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


 557      * @param sm The stream metadata or {@code null} if
 558      * {@code writeHeader} is {@code false}.
 559      * @param iioimage The image and image metadata.
 560      * @param p The write parameters.
 561      *
 562      * @throws IllegalArgumentException if the number of bands is not 1.
 563      * @throws IllegalArgumentException if the number of bits per sample is
 564      * greater than 8.
 565      * @throws IllegalArgumentException if the color component size is
 566      * greater than 8.
 567      * @throws IllegalArgumentException if {@code writeHeader} is
 568      * {@code true} and {@code sm} is {@code null}.
 569      * @throws IllegalArgumentException if {@code writeHeader} is
 570      * {@code false} and a sequence is not being written.
 571      */
 572     private void write(boolean writeHeader,
 573                        boolean writeTrailer,
 574                        IIOMetadata sm,
 575                        IIOImage iioimage,
 576                        ImageWriteParam p) throws IOException {

 577 
 578         RenderedImage image = iioimage.getRenderedImage();
 579 
 580         // Check for ability to encode image.
 581         if (needToCreateIndex(image)) {
 582             image = PaletteBuilder.createIndexedImage(image);
 583             iioimage.setRenderedImage(image);
 584         }
 585 
 586         ColorModel colorModel = image.getColorModel();
 587         SampleModel sampleModel = image.getSampleModel();
 588 
 589         // Determine source region and destination dimensions.
 590         Rectangle sourceBounds = new Rectangle(image.getMinX(),
 591                                                image.getMinY(),
 592                                                image.getWidth(),
 593                                                image.getHeight());
 594         Dimension destSize = new Dimension();
 595         computeRegions(sourceBounds, destSize, p);
 596 


 811         // Write image data
 812         writeRasterData(image, sourceBounds, destSize,
 813                         param, imageMetadata.interlaceFlag);
 814     }
 815 
 816     private void writeRows(RenderedImage image, LZWCompressor compressor,
 817                            int sx, int sdx, int sy, int sdy, int sw,
 818                            int dy, int ddy, int dw, int dh,
 819                            int numRowsWritten, int progressReportRowPeriod)
 820       throws IOException {
 821         if (DEBUG) System.out.println("Writing unoptimized");
 822 
 823         int[] sbuf = new int[sw];
 824         byte[] dbuf = new byte[dw];
 825 
 826         Raster raster =
 827             image.getNumXTiles() == 1 && image.getNumYTiles() == 1 ?
 828             image.getTile(0, 0) : image.getData();
 829         for (int y = dy; y < dh; y += ddy) {
 830             if (numRowsWritten % progressReportRowPeriod == 0) {
 831                 processImageProgress((numRowsWritten*100.0F)/dh);
 832                 if (abortRequested()) {
 833                     processWriteAborted();
 834                     return;
 835                 }

 836             }
 837 
 838             raster.getSamples(sx, sy, sw, 1, 0, sbuf);
 839             for (int i = 0, j = 0; i < dw; i++, j += sdx) {
 840                 dbuf[i] = (byte)sbuf[j];
 841             }
 842             compressor.compress(dbuf, 0, dw);
 843             numRowsWritten++;
 844             sy += sdy;
 845         }
 846     }
 847 
 848     private void writeRowsOpt(byte[] data, int offset, int lineStride,
 849                               LZWCompressor compressor,
 850                               int dy, int ddy, int dw, int dh,
 851                               int numRowsWritten, int progressReportRowPeriod)
 852       throws IOException {
 853         if (DEBUG) System.out.println("Writing optimized");
 854 
 855         offset += dy*lineStride;
 856         lineStride *= ddy;
 857         for (int y = dy; y < dh; y += ddy) {
 858             if (numRowsWritten % progressReportRowPeriod == 0) {
 859                 processImageProgress((numRowsWritten*100.0F)/dh);
 860                 if (abortRequested()) {
 861                     processWriteAborted();
 862                     return;
 863                 }

 864             }
 865 
 866             compressor.compress(data, offset, dw);
 867             numRowsWritten++;
 868             offset += lineStride;
 869         }
 870     }
 871 
 872     private void writeRasterData(RenderedImage image,
 873                                  Rectangle sourceBounds,
 874                                  Dimension destSize,
 875                                  ImageWriteParam param,
 876                                  boolean interlaceFlag) throws IOException {
 877 
 878         int sourceXOffset = sourceBounds.x;
 879         int sourceYOffset = sourceBounds.y;
 880         int sourceWidth = sourceBounds.width;
 881         int sourceHeight = sourceBounds.height;
 882 
 883         int destWidth = destSize.width;


 906             new LZWCompressor(stream, initCodeSize, false);
 907 
 908         /* At this moment we know that input image is indexed image.
 909          * We can directly copy data iff:
 910          *   - no subsampling required (periodX = 1, periodY = 0)
 911          *   - we can access data directly (image is non-tiled,
 912          *     i.e. image data are in single block)
 913          *   - we can calculate offset in data buffer (next 3 lines)
 914          */
 915         boolean isOptimizedCase =
 916             periodX == 1 && periodY == 1 &&
 917             image.getNumXTiles() == 1 && image.getNumYTiles() == 1 &&
 918             sampleModel instanceof ComponentSampleModel &&
 919             image.getTile(0, 0) instanceof ByteComponentRaster &&
 920             image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte;
 921 
 922         int numRowsWritten = 0;
 923 
 924         int progressReportRowPeriod = Math.max(destHeight/20, 1);
 925 
 926         clearAbortRequest();
 927         processImageStarted(imageIndex);
 928         if (abortRequested()) {
 929             processWriteAborted();
 930             return;
 931         }
 932 
 933         if (interlaceFlag) {
 934             if (DEBUG) System.out.println("Writing interlaced");
 935 
 936             if (isOptimizedCase) {
 937                 ByteComponentRaster tile =
 938                     (ByteComponentRaster)image.getTile(0, 0);
 939                 byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData();
 940                 ComponentSampleModel csm =
 941                     (ComponentSampleModel)tile.getSampleModel();
 942                 int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0);
 943                 // take into account the raster data offset
 944                 offset += tile.getDataOffset(0);
 945                 int lineStride = csm.getScanlineStride();
 946 
 947                 writeRowsOpt(data, offset, lineStride, compressor,
 948                              0, 8, destWidth, destHeight,
 949                              numRowsWritten, progressReportRowPeriod);
 950 
 951                 if (abortRequested()) {


 960 
 961                 if (abortRequested()) {
 962                     return;
 963                 }
 964 
 965                 numRowsWritten += (destHeight - 4)/8;
 966 
 967                 writeRowsOpt(data, offset, lineStride, compressor,
 968                              2, 4, destWidth, destHeight,
 969                              numRowsWritten, progressReportRowPeriod);
 970 
 971                 if (abortRequested()) {
 972                     return;
 973                 }
 974 
 975                 numRowsWritten += (destHeight - 2)/4;
 976 
 977                 writeRowsOpt(data, offset, lineStride, compressor,
 978                              1, 2, destWidth, destHeight,
 979                              numRowsWritten, progressReportRowPeriod);
 980                 if (abortRequested()) {
 981                     return;
 982                 }
 983             } else {
 984                 writeRows(image, compressor,
 985                           sourceXOffset, periodX,
 986                           sourceYOffset, 8*periodY,
 987                           sourceWidth,
 988                           0, 8, destWidth, destHeight,
 989                           numRowsWritten, progressReportRowPeriod);
 990 
 991                 if (abortRequested()) {
 992                     return;
 993                 }
 994 
 995                 numRowsWritten += destHeight/8;
 996 
 997                 writeRows(image, compressor, sourceXOffset, periodX,
 998                           sourceYOffset + 4*periodY, 8*periodY,
 999                           sourceWidth,
1000                           4, 8, destWidth, destHeight,
1001                           numRowsWritten, progressReportRowPeriod);
1002 


1006 
1007                 numRowsWritten += (destHeight - 4)/8;
1008 
1009                 writeRows(image, compressor, sourceXOffset, periodX,
1010                           sourceYOffset + 2*periodY, 4*periodY,
1011                           sourceWidth,
1012                           2, 4, destWidth, destHeight,
1013                           numRowsWritten, progressReportRowPeriod);
1014 
1015                 if (abortRequested()) {
1016                     return;
1017                 }
1018 
1019                 numRowsWritten += (destHeight - 2)/4;
1020 
1021                 writeRows(image, compressor, sourceXOffset, periodX,
1022                           sourceYOffset + periodY, 2*periodY,
1023                           sourceWidth,
1024                           1, 2, destWidth, destHeight,
1025                           numRowsWritten, progressReportRowPeriod);
1026                 if (abortRequested()) {
1027                     return;
1028                 }
1029             }
1030         } else {
1031             if (DEBUG) System.out.println("Writing non-interlaced");
1032 
1033             if (isOptimizedCase) {
1034                 Raster tile = image.getTile(0, 0);
1035                 byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData();
1036                 ComponentSampleModel csm =
1037                     (ComponentSampleModel)tile.getSampleModel();
1038                 int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0);
1039                 int lineStride = csm.getScanlineStride();
1040 
1041                 writeRowsOpt(data, offset, lineStride, compressor,
1042                              0, 1, destWidth, destHeight,
1043                              numRowsWritten, progressReportRowPeriod);
1044                 if (abortRequested()) {
1045                     return;
1046                 }
1047             } else {
1048                 writeRows(image, compressor,
1049                           sourceXOffset, periodX,
1050                           sourceYOffset, periodY,
1051                           sourceWidth,
1052                           0, 1, destWidth, destHeight,
1053                           numRowsWritten, progressReportRowPeriod);



1054                 if (abortRequested()) {
1055                     return;
1056                 }
1057             }
1058         }
1059 
1060         compressor.flush();
1061 
1062         stream.write(0x00);
1063 
1064         processImageComplete();
1065     }
1066 
1067     private void writeHeader(String version,
1068                              int logicalScreenWidth,
1069                              int logicalScreenHeight,
1070                              int colorResolution,
1071                              int pixelAspectRatio,
1072                              int backgroundColorIndex,
1073                              boolean sortFlag,
1074                              int bitsPerPixel,
1075                              byte[] globalColorTable) throws IOException {
1076         try {
1077             // Signature
1078             stream.writeBytes("GIF"+version);


< prev index next >