static void maskedSubsample(const GPixmap* img, const GBitmap *p_mask, GPixmap& subsampled_image, GBitmap& subsampled_mask, int gridwidth, int inverted_mask, int minpixels=1 ) { const GPixmap& image= *img; const GBitmap& mask = *p_mask; int imageheight = image.rows(); int imagewidth = image.columns(); // compute the size of the resulting subsampled image int subheight = imageheight/gridwidth; if(imageheight%gridwidth) subheight++; int subwidth = imagewidth/gridwidth; if(imagewidth%gridwidth) subwidth++; // set the sizes unless in incremental mode subsampled_image.init(subheight, subwidth); subsampled_mask.init(subheight, subwidth); // go subsampling int row, col; // row and col in the subsampled image int posx, posxend, posy, posyend; // corresponding square in the original image for(row=0, posy=0; row<subheight; row++, posy+=gridwidth) { GPixel* subsampled_image_row = subsampled_image[row]; // row row of subsampled image unsigned char* subsampled_mask_row = subsampled_mask[row]; // row row of subsampled mask posyend = posy+gridwidth; if(posyend>imageheight) posyend = imageheight; for(col=0, posx=0; col<subwidth; col++, posx+=gridwidth) { posxend = posx+gridwidth; if(posxend>imagewidth) posxend = imagewidth; int count = 0; int r = 0; int g = 0; int b = 0; for(int y=posy; y<posyend; y++) { const unsigned char* mask_y = mask[y]; // Row y of the mask for(int x=posx; x<posxend; x++) { unsigned char masked = (inverted_mask ? !mask_y[x] :mask_y[x]); if(!masked) { GPixel p = image[y][x]; r += p.r; g += p.g; b += p.b; count ++; } } } /* minpixels pixels are enough to give the color */ /* so set it, and do not mask this point */ if(count >= minpixels) { GPixel p; p.r = r/count; p.g = g/count; p.b = b/count; subsampled_image_row[col] = p; subsampled_mask_row[col] = 0; } else /* make it bright red and masked */ { subsampled_image_row[col] = GPixel::RED; subsampled_mask_row[col] = 1; } } } }
void JPEGDecoder::decode(ByteStream & bs,GPixmap &pix) { struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. */ struct djvu_error_mgr jerr; JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ int full_buf_size; int isGrey,i; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = djvu_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); G_THROW( ERR_MSG("GPixmap.unk_PPM") ); } jpeg_create_decompress(&cinfo); Impl::jpeg_byte_stream_src(&cinfo, bs); (void) jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; full_buf_size = row_stride * cinfo.output_height; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); GP<ByteStream> goutputBlock=ByteStream::create(); ByteStream &outputBlock=*goutputBlock; outputBlock.format("P6\n%d %d\n%d\n",cinfo.output_width, cinfo.output_height,255); isGrey = ( cinfo.out_color_space == JCS_GRAYSCALE) ? 1 : 0; while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); if ( isGrey == 1 ) { for (i=0; i<row_stride; i++) { outputBlock.write8((char)buffer[0][i]); outputBlock.write8((char)buffer[0][i]); outputBlock.write8((char)buffer[0][i]); } }else { for (i=0; i<row_stride; i++) outputBlock.write8((char)buffer[0][i]); } } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); outputBlock.seek(0,SEEK_SET); pix.init(outputBlock); }