3636import java .io .IOException ;
3737import java .util .Map ;
3838
39- import javajs .img .ImageEncoder ;
4039import javajs .util .AU ;
4140import javajs .util .OC ;
4241
@@ -65,7 +64,7 @@ public class JpgEncoder extends ImageEncoder {
6564 private JpegObj jpegObj ;
6665 private Huffman huf ;
6766 private DCT dct ;
68- protected int defaultQuality = 100 ;
67+ protected int defaultQuality = 100 ; // set to 75 for Base64
6968 private String applicationTag ;
7069
7170 public JpgEncoder () {
@@ -74,11 +73,19 @@ public JpgEncoder() {
7473
7574 @ Override
7675 protected void setParams (Map <String , Object > params ) {
77- if (quality <= 0 )
78- quality = (params .containsKey ("qualityJPG" ) ? ((Integer ) params .get ("qualityJPG" )).intValue () : defaultQuality );
7976 jpegObj = new JpegObj ();
8077 jpegObj .comment = (String ) params .get ("comment" );
8178 applicationTag = (String ) params .get ("jpgAppTag" );
79+ dpi = 300 ;
80+ if (quality <= 0 )
81+ quality = (params .containsKey ("qualityJPG" ) ? ((Integer ) params .get ("qualityJPG" )).intValue () : -1 );
82+ if (quality >= 90 ) {
83+ // 96, 100, 200, 300, 600, etc.
84+ dpi = quality ;
85+ quality = -1 ;
86+ }
87+ if (quality < 0 )
88+ quality = defaultQuality ;
8289 }
8390
8491 @ Override
@@ -186,24 +193,33 @@ private void writeCompressedData(JpegObj jpegObj, DCT dct, Huffman huf) {
186193 private static byte [] eoi = { (byte ) 0xFF , (byte ) 0xD9 };
187194
188195 private static byte [] jfif = new byte [] {
189- /* JFIF[0] =*/ (byte ) 0xff ,
190- /* JFIF[1] =*/ (byte ) 0xe0 ,
191- /* JFIF[2] =*/ 0 ,
192- /* JFIF[3] =*/ 16 ,
193- /* JFIF[4] =*/ (byte ) 0x4a , //'J'
196+ // application use marker
197+ /* JFIF[0] =*/ (byte ) 0xff ,
198+ /* JFIF[1] =*/ (byte ) 0xe0 ,
199+ // APP0 field size; starting at [2]
200+ /* JFIF[2] =*/ 0 ,
201+ /* JFIF[3] =*/ 16 ,
202+
203+ /* JFIF[4] =*/ (byte ) 0x4a , //'J'
194204 /* JFIF[5] =*/ (byte ) 0x46 , //'F'
195205 /* JFIF[6] =*/ (byte ) 0x49 , //'I'
196206 /* JFIF[7] =*/ (byte ) 0x46 , //'F'
197207 /* JFIF[8] =*/ 0 ,
208+
198209 /* JFIF[9] =*/ 1 ,
199210 /* JFIF[10] =*/ 0 ,
200- /* JFIF[11] =*/ 0 ,
201- /* JFIF[12] =*/ 0 ,
202- /* JFIF[13] =*/ 1 ,
203- /* JFIF[14] =*/ 0 ,
204- /* JFIF[15] =*/ 1 ,
205- /* JFIF[16] =*/ 0 ,
206- /* JFIF[17] =*/ 0 };
211+
212+ // quality (5 bytes) and thumbnail (2 bytes) follow; not included here
213+ };
214+
215+
216+ // BYTE Identifier[5]; /* 06h "JFIF" (zero terminated) Id String */
217+ // BYTE Version[2]; /* 07h JFIF Format Revision */
218+ // BYTE Units; /* 09h Units used for Resolution */
219+ // BYTE Xdensity[2]; /* 0Ah Horizontal Resolution */
220+ // BYTE Ydensity[2]; /* 0Ch Vertical Resolution */
221+ // BYTE XThumbnail; /* 0Eh Horizontal Pixel Count */
222+ // BYTE YThumbnail; /* 0Fh Vertical Pixel Count */
207223
208224 private static byte [] soi = { (byte ) 0xFF , (byte ) 0xD8 };
209225
@@ -217,6 +233,9 @@ private String writeHeaders(JpegObj jpegObj, DCT dct) {
217233 // The order of the following headers is quite inconsequential.
218234 // the JFIF header
219235 writeArray (jfif );
236+
237+ writeDensities ();
238+ writeThumbNailSize ();
220239
221240 // Comment Header
222241 String comment = null ;
@@ -287,6 +306,30 @@ private String writeHeaders(JpegObj jpegObj, DCT dct) {
287306 return comment ;
288307 }
289308
309+ private void writeDensities () {
310+ // Units, Xdensity, and Ydensity identify the unit of measurement
311+ // used to describe the image resolution.
312+ // Units may be 01h for dots per inch,
313+ // 02h for dots per centimeter,
314+ // or 00h for none (use measurement as pixel aspect ratio).
315+ // Xdensity and Ydensity are the horizontal and vertical resolution
316+ // of the image data, respectively.
317+ // If the Units field value is 00h, the Xdensity and Ydensity fields
318+ // will contain the pixel aspect ratio (Xdensity : Ydensity)
319+ // rather than the image resolution.
320+ // Because non-square pixels are discouraged for portability
321+ // reasons, the Xdensity and Ydensity values normally
322+ // equal 1 when the Units value is 0.
323+
324+ out .writeByteAsInt (1 );
325+ out .writeShort ((short ) dpi );
326+ out .writeShort ((short ) dpi );
327+ }
328+
329+ private void writeThumbNailSize () {
330+ writeArray (new byte [2 ]);
331+ }
332+
290333 private void writeString (String s , byte id ) {
291334 int len = s .length ();
292335 int i0 = 0 ;
0 commit comments