//C- ------------------------------------------------------------------- //C- Java DjVu (r) (v. 0.8) //C- Copyright (c) 2004-2005 LizardTech, Inc. All Rights Reserved. //C- Java DjVu is protected by U.S. Pat. No.C- 6,058,214 and patents //C- pending. //C- //C- This software is subject to, and may be distributed under, the //C- GNU General Public License, Version 2. The license should have //C- accompanied the software or you may obtain a copy of the license //C- from the Free Software Foundation at http://www.fsf.org . //C- //C- The computer code originally released by LizardTech under this //C- license and unmodified by other parties is deemed "the LIZARDTECH //C- ORIGINAL CODE." Subject to any third party intellectual property //C- claims, LizardTech grants recipient a worldwide, royalty-free, //C- non-exclusive license to make, use, sell, or otherwise dispose of //C- the LIZARDTECH ORIGINAL CODE or of programs derived from the //C- LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU //C- General Public License. This grant only confers the right to //C- infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to //C- the extent such infringement is reasonably necessary to enable //C- recipient to make, have made, practice, sell, or otherwise dispose //C- of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to //C- any greater extent that may be necessary to utilize further //C- modifications or combinations. //C- //C- The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY //C- OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED //C- TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF //C- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. //C- //C- In addition, as a special exception, LizardTech Inc. gives permission //C- to link the code of this program with the proprietary Java //C- implementation provided by Sun (or other vendors as well), and //C- distribute linked combinations including the two. You must obey the //C- GNU General Public License in all respects for all of the code used //C- other than the proprietary Java implementation. If you modify this //C- file, you may extend this exception to your version of the file, but //C- you are not obligated to do so. If you do not wish to do so, delete //C- this exception statement from your version. //C- ------------------------------------------------------------------- //C- Developed by Bill C. Riemers, Foxtrot Technologies Inc. as work for //C- hire under US copyright laws. //C- ------------------------------------------------------------------- // package com.lizardtech.djvu; import com.google.gwt.typedarrays.shared.Int16Array; import com.google.gwt.typedarrays.shared.TypedArrays; import com.google.gwt.typedarrays.shared.Uint8Array; /** * This class represents structured wavelette data. */ final class IWMap { //~ Instance fields -------------------------------------------------------- /** DOCUMENT ME! */ protected IWBlock[] blocks; /** DOCUMENT ME! */ protected int bh; /** DOCUMENT ME! */ protected int bw; /** DOCUMENT ME! */ protected int ih; /** DOCUMENT ME! */ protected int iw; /** DOCUMENT ME! */ protected int nb; /** DOCUMENT ME! */ protected int top; //~ Constructors ----------------------------------------------------------- /** * Creates a new IWMap object. */ public IWMap() {} /** * Creates a new IWMap object. * * @param w DOCUMENT ME! * @param h DOCUMENT ME! */ public IWMap( final int w, final int h) { init(w, h); } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @param p DOCUMENT ME! * @param pidx DOCUMENT ME! * @param w DOCUMENT ME! * @param h DOCUMENT ME! * @param rowsize DOCUMENT ME! * @param begin DOCUMENT ME! * @param end DOCUMENT ME! */ static void backward( Int16Array p, int pidx, int w, int h, int rowsize, int begin, int end) { for(int scale = begin >> 1; scale >= end; scale >>= 1) { for(int j = 0; j < w; j += scale) { backward_filter(p, pidx, j, j + (h * rowsize), j, scale * rowsize); } for(int i = 0; i < h; i += scale) { backward_filter( p, pidx, i * rowsize, (i * rowsize) + w, i * rowsize, scale); } } } /** * DOCUMENT ME! * * @param p DOCUMENT ME! * @param pidx DOCUMENT ME! * @param b DOCUMENT ME! * @param e DOCUMENT ME! * @param z DOCUMENT ME! * @param s DOCUMENT ME! */ static void backward_filter( Int16Array p, int pidx, int b, int e, int z, int s) { final int s3 = 3 * s; if((z < b) || (z > e)) { Utils.logError( "(_IWCoeff::backward_filter) Out of bounds [b<=z<=e]"); } int n = z; int bb; int cc; int aa = bb = cc = 0; int dd = ((n + s) >= e) ? 0 : ((int)(p.get(pidx + n + s))); for(; (n + s3) < e; n = (n + s3) - s) { aa = bb; bb = cc; cc = dd; dd = p.get(pidx + n + s3); p.set(pidx + n, p.get(pidx + n) - ((((9 * (bb + cc)) - (aa + dd)) + 16) >> 5)); } for(; n < e; n = n + s + s) { aa = bb; bb = cc; cc = dd; dd = 0; p.set(pidx + n, p.get(pidx + n) - ((((9 * (bb + cc)) - (aa + dd)) + 16) >> 5));; } n = z + s; aa = 0; bb = p.get((pidx + n) - s); cc = ((n + s) >= e) ? 0 : ((int)(p.get(pidx + n + s))); dd = ((n + s3) >= e) ? 0 : ((int)(p.get(pidx + n + s3))); if(n < e) { int x = bb; if((n + s) < e) { x = (bb + cc + 1) >> 1; } p.set(pidx + n, p.get(pidx + n) + x); n = n + s + s; } for(; (n + s3) < e; n = (n + s3) - s) { aa = bb; bb = cc; cc = dd; dd = p.get(pidx + n + s3); int x = (((9 * (bb + cc)) - (aa + dd)) + 8) >> 4; p.set(pidx + n, p.get(pidx + n) + x); } if((n + s) < e) { aa = bb; bb = cc; cc = dd; dd = 0; int x = (bb + cc + 1) >> 1; p.set(pidx + n, p.get(pidx + n) + x); n = n + s + s; } if(n < e) { aa = bb; bb = cc; cc = dd; dd = 0; int x = bb; p.set(pidx + n, p.get(pidx + n) + x); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ int get_bucket_count() { int buckets = 0; for(int blockno = 0; blockno < nb; blockno++) { for(int buckno = 0; buckno < 64; buckno++) { if(blocks[blockno].getBlock(buckno) != null) { buckets++; } } } return buckets; } /** * DOCUMENT ME! * * @param index DOCUMENT ME! * @param img8 DOCUMENT ME! * @param rowsize DOCUMENT ME! * @param pixsep DOCUMENT ME! * @param fast DOCUMENT ME! */ void image( int index, final Uint8Array img8, int rowsize, int pixsep, boolean fast) { final Int16Array data16 = TypedArrays.createInt16Array(bw * bh); final Int16Array liftblock = TypedArrays.createInt16Array(1024); int pidx = 0; IWBlock[] block = blocks; int blockidx = 0; int ppidx = 0; for(int i = 0; i < bh; i += 32, pidx += (32 * bw)) { for(int j = 0; j < bw; j += 32) { block[blockidx].write_liftblock(liftblock, 0, 64); blockidx++; ppidx = pidx + j; for(int ii = 0, p1idx = 0; ii++ < 32; p1idx += 32, ppidx += bw) { Int16Array src = liftblock.subarray(p1idx, p1idx + 32); data16.set(src, ppidx); } } } if(fast) { backward(data16, 0, iw, ih, bw, 32, 2); pidx = 0; for(int i = 0; i < bh; i += 2, pidx += bw) { for(int jj = 0; jj < bw; jj += 2, pidx += 2) { short s = data16.get(pidx); data16.set(pidx + bw, s); data16.set(pidx + bw + 1, s); data16.set(pidx + 1, s); } } } else { backward(data16, 0, iw, ih, bw, 32, 1); } pidx = 0; for(int i = 0, rowidx = index; i++ < ih; rowidx += rowsize, pidx += bw) { for(int j = 0, pixidx = rowidx; j < iw; pixidx += pixsep) { int x = (data16.get(pidx + (j++)) + 32) >> 6; if(x < -128) { x = -128; } else if(x > 127) { x = 127; } img8.set(pixidx, x); } } } /** * DOCUMENT ME! * * @param subsample DOCUMENT ME! * @param rect DOCUMENT ME! * @param index DOCUMENT ME! * @param img8 DOCUMENT ME! * @param rowsize DOCUMENT ME! * @param pixsep DOCUMENT ME! * @param fast DOCUMENT ME! * * @throws IllegalArgumentException DOCUMENT ME! */ void image( int subsample, GRect rect, int index, final Uint8Array img8, int rowsize, int pixsep, boolean fast) { int nlevel = 0; while((nlevel < 5) && ((32 >> nlevel) > subsample)) { nlevel++; } final int boxsize = 1 << nlevel; if(subsample != (32 >> nlevel)) { throw new IllegalArgumentException( "(IWMap::image) Unsupported subsampling factor"); } if(rect.isEmpty()) { throw new IllegalArgumentException("(IWMap::image) GRect is empty"); } GRect irect = new GRect( 0, 0, ((iw + subsample) - 1) / subsample, ((ih + subsample) - 1) / subsample); if( (rect.xmin < 0) || (rect.ymin < 0) || (rect.xmax > irect.xmax) || (rect.ymax > irect.ymax)) { throw new IllegalArgumentException( "(IWMap::image) GRect is out of bounds: " + rect.xmin + "," + rect.ymin + "," + rect.xmax + "," + rect.ymax + "," + irect.xmax + "," + irect.ymax); } GRect[] needed = new GRect[8]; GRect[] recomp = new GRect[8]; for(int i = 0; i < 8;) { needed[i] = new GRect(); recomp[i++] = new GRect(); } int r = 1; needed[nlevel] = new GRect(rect); recomp[nlevel] = new GRect(rect); for(int i = nlevel - 1; i >= 0; i--) { needed[i] = recomp[i + 1]; needed[i].inflate(3 * r, 3 * r); needed[i].intersect(needed[i], irect); r += r; recomp[i].xmin = ((needed[i].xmin + r) - 1) & ~(r - 1); recomp[i].xmax = needed[i].xmax & ~(r - 1); recomp[i].ymin = ((needed[i].ymin + r) - 1) & ~(r - 1); recomp[i].ymax = needed[i].ymax & ~(r - 1); } GRect work = new GRect(); work.xmin = needed[0].xmin & ~(boxsize - 1); work.ymin = needed[0].ymin & ~(boxsize - 1); work.xmax = ((needed[0].xmax - 1) & ~(boxsize - 1)) + boxsize; work.ymax = ((needed[0].ymax - 1) & ~(boxsize - 1)) + boxsize; final int dataw = work.width(); final Int16Array data = TypedArrays.createInt16Array(dataw * work.height()); int blkw = bw >> 5; int lblock = ((work.ymin >> nlevel) * blkw) + (work.xmin >> nlevel); final Int16Array liftblock = TypedArrays.createInt16Array(1024); for( int by = work.ymin, ldata = 0; by < work.ymax; by += boxsize, ldata += (dataw << nlevel), lblock += blkw) { for( int bx = work.xmin, bidx = lblock, rdata = ldata; bx < work.xmax; bx += boxsize, bidx++, rdata += boxsize) { IWBlock block = blocks[bidx]; int mlevel = nlevel; if( (nlevel > 2) && (((bx + 31) < needed[2].xmin) || (bx > needed[2].xmax) || ((by + 31) < needed[2].ymin) || (by > needed[2].ymax))) { mlevel = 2; } final int bmax = ((1 << (mlevel + mlevel)) + 15) >> 4; final int ppinc = 1 << (nlevel - mlevel); final int ppmod1 = dataw << (nlevel - mlevel); final int ttmod0 = 32 >> mlevel; final int ttmod1 = ttmod0 << 5; block.write_liftblock(liftblock, 0, bmax); for( int ii = 0, tt = 0, pp = rdata; ii < boxsize; ii += ppinc, pp += ppmod1, tt += (ttmod1 - 32)) { for(int jj = 0; jj < boxsize; jj += ppinc, tt += ttmod0) { data.set(pp + jj, liftblock.get(tt)); } } } } r = boxsize; for(int i = 0; i < nlevel; i++) { GRect comp = needed[i]; comp.xmin = comp.xmin & ~(r - 1); comp.ymin = comp.ymin & ~(r - 1); comp.translate(-work.xmin, -work.ymin); if(fast&& (i >= 4)) { workaround(dataw, data, comp); break; } backward( data, (comp.ymin * dataw) + comp.xmin, comp.width(), comp.height(), dataw, r, r >> 1); r >>= 1; } GRect nrect = new GRect(rect); nrect.translate(-work.xmin, -work.ymin); for( int i = nrect.ymin, pidx = (nrect.ymin * dataw), ridx = index; i++ < nrect.ymax; ridx += rowsize, pidx += dataw) { for( int j = nrect.xmin, pixidx = ridx; j < nrect.xmax; j++, pixidx += pixsep) { int x = (data.get(pidx + j) + 32) >> 6; if(x < -128) { x = -128; } else if(x > 127) { x = 127; } img8.set(pixidx, x); } } } /** * This must be a separate method to work around issue * https://code.google.com/p/google-web-toolkit/issues/detail?id=9184 */ private void workaround(final int dataw, final Int16Array data, GRect comp) { int pp = (comp.ymin * dataw); for (int ii = comp.ymin; ii < comp.ymax; ii += 2) { for (int jj = comp.xmin; jj < comp.xmax; jj += 2) { short s = data.get(pp + jj); data.set(pp + jj + dataw, s); data.set(pp + jj + dataw + 1, s); data.set(pp + jj + 1, s); } pp += (dataw + dataw); } } /** * DOCUMENT ME! * * @param w DOCUMENT ME! * @param h DOCUMENT ME! * * @return DOCUMENT ME! */ IWMap init( final int w, final int h) { iw = w; ih = h; bw = ((w + 32) - 1) & 0xffffffe0; bh = ((h + 32) - 1) & 0xffffffe0; nb = (bw * bh) / 1024; blocks = new IWBlock[nb]; for(int i = 0; i < nb; i++) { blocks[i] = new IWBlock(); } return this; } }