Beispiel #1
0
func makeSourceManager(src io.Reader, dinfo *C.struct_jpeg_decompress_struct) (mgr *sourceManager) {
	mgr = new(sourceManager)
	mgr.src = src
	mgr.pub = C.malloc_jpeg_source_mgr()
	if mgr.pub == nil {
		panic("Failed to allocate C.struct_jpeg_source_mgr")
	}
	mgr.buffer = C.malloc(readBufferSize)
	if mgr.buffer == nil {
		panic("Failed to allocate buffer")
	}
	mgr.pub.init_source = (*[0]byte)(C.sourceInit)
	mgr.pub.fill_input_buffer = (*[0]byte)(C.sourceFill)
	mgr.pub.skip_input_data = (*[0]byte)(C.sourceSkip)
	mgr.pub.resync_to_restart = (*[0]byte)(C._get_jpeg_resync_to_restart())
	mgr.pub.term_source = (*[0]byte)(C.sourceTerm)
	mgr.pub.bytes_in_buffer = 0
	mgr.pub.next_input_byte = nil
	dinfo.src = mgr.pub

	sourceManagerMapMutex.Lock()
	defer sourceManagerMapMutex.Unlock()
	sourceManagerMap[uintptr(unsafe.Pointer(mgr.pub))] = mgr

	return
}
Beispiel #2
0
// TODO: supports decoding into image.RGBA instead of rgb.Image.
func decodeRGB(dinfo *C.struct_jpeg_decompress_struct) (dest *rgb.Image, err error) {
	C.jpeg_calc_output_dimensions(dinfo)
	dest = rgb.NewImage(image.Rect(0, 0, int(dinfo.output_width), int(dinfo.output_height)))

	dinfo.out_color_space = C.JCS_RGB
	readScanLines(dinfo, dest.Pix, dest.Stride)
	return
}
Beispiel #3
0
func Decode(r io.Reader) (img image.Image, er error) {
	/* Reading the whole file in may be inefficient, but libjpeg wants callbacks
	 * to functions to read in more data, and that is a nightmare to implement. We
	 * don't want to read the entire stream, however, which means pulling the header.
	 * We may be able to read enough to call jpeg_read_header with a [10]byte, but
	 * I'll change it later if need be, since this probably doesn't play nicely
	 * with a non-closing io.Reader */

	var wholeFile []byte
	if wholeFile, er = ioutil.ReadAll(r); er != nil {
		return
	}

	var cinfo C.struct_jpeg_decompress_struct
	var jerr C.struct_jpeg_error_mgr

	cinfo.err = C.jpeg_std_error(&jerr)
	C.jpeg_CreateDecompress(&cinfo, C.JPEG_LIB_VERSION, C.size_t(unsafe.Sizeof(cinfo)))

	C.jpeg_mem_src(&cinfo, (*C.uchar)(unsafe.Pointer(&wholeFile[0])), C.ulong(len(wholeFile)))

	if C.jpeg_read_header(&cinfo, C.TRUE) == C.JPEG_HEADER_OK {
		C.jpeg_start_decompress(&cinfo)

		if cinfo.num_components == 1 {
			img = decodeGrayscale(&cinfo)

		} else if cinfo.num_components == 3 {
			img = decodeRGB(&cinfo)

		} else if cinfo.num_components == 4 {
			img = decodeCMYK(&cinfo)

		} else {
			er = fmt.Errorf("Invalid number of components (%d)", cinfo.num_components)
		}

		if er == nil {
			C.jpeg_finish_decompress(&cinfo)
		}
	}

	C.jpeg_destroy_decompress(&cinfo)

	return
}
Beispiel #4
0
func setupDecoderOptions(dinfo *C.struct_jpeg_decompress_struct, opt *DecoderOptions) {
	tw, th := opt.ScaleTarget.Dx(), opt.ScaleTarget.Dy()
	if tw > 0 && th > 0 {
		var scaleFactor int
		for scaleFactor = 1; scaleFactor <= 8; scaleFactor++ {
			if ((scaleFactor*int(dinfo.image_width)+7)/8) >= tw &&
				((scaleFactor*int(dinfo.image_height)+7)/8) >= th {
				break
			}
		}
		if scaleFactor < 8 {
			dinfo.scale_num = C.uint(scaleFactor)
			dinfo.scale_denom = 8
		}
	}

	dinfo.dct_method = C.J_DCT_METHOD(opt.DCTMethod)
	if opt.DisableFancyUpsampling {
		dinfo.do_fancy_upsampling = C.FALSE
	} else {
		dinfo.do_fancy_upsampling = C.TRUE
	}
	if opt.DisableBlockSmoothing {
		dinfo.do_block_smoothing = C.FALSE
	} else {
		dinfo.do_block_smoothing = C.TRUE
	}
}
Beispiel #5
0
func decodeGray(dinfo *C.struct_jpeg_decompress_struct) (dest *image.Gray, err error) {
	// output dawnsampled raw data before starting decompress
	dinfo.raw_data_out = C.TRUE

	C.jpeg_start_decompress(dinfo)

	compInfo := (*[1]C.jpeg_component_info)(unsafe.Pointer(dinfo.comp_info))
	dest = NewGrayAligned(image.Rect(0, 0, int(compInfo[0].downsampled_width), int(compInfo[0].downsampled_height)))

	iMCURows := int(C.DCT_v_scaled_size(dinfo, C.int(0)) * compInfo[0].v_samp_factor)

	C.decode_gray(dinfo, C.JSAMPROW(unsafe.Pointer(&dest.Pix[0])), C.int(dest.Stride), C.int(iMCURows))

	C.jpeg_finish_decompress(dinfo)
	return
}
Beispiel #6
0
func makeSourceManager(src io.Reader, dinfo *C.struct_jpeg_decompress_struct) (ret *sourceManager) {
	ret = (*sourceManager)(C.malloc(C.size_t(unsafe.Sizeof(sourceManager{}))))
	if ret == nil {
		panic("Failed to allocate sourceManager")
	}
	ret.magic = magic
	ret.src = src
	ret.pub.init_source = (*[0]byte)(C.sourceInit)
	ret.pub.fill_input_buffer = (*[0]byte)(C.sourceFill)
	ret.pub.skip_input_data = (*[0]byte)(C.sourceSkip)
	ret.pub.resync_to_restart = (*[0]byte)(C.jpeg_resync_to_restart) // default implementation
	ret.pub.term_source = (*[0]byte)(C.sourceTerm)
	ret.pub.bytes_in_buffer = 0
	ret.pub.next_input_byte = nil
	dinfo.src = &ret.pub
	return
}
Beispiel #7
0
func decodeYCbCr(dinfo *C.struct_jpeg_decompress_struct) (dest *image.YCbCr, err error) {
	// output dawnsampled raw data before starting decompress
	dinfo.raw_data_out = C.TRUE

	C.jpeg_start_decompress(dinfo)

	compInfo := (*[3]C.jpeg_component_info)(unsafe.Pointer(dinfo.comp_info))

	dwY := compInfo[Y].downsampled_width
	dhY := compInfo[Y].downsampled_height
	dwC := compInfo[Cb].downsampled_width
	dhC := compInfo[Cb].downsampled_height
	//fmt.Printf("%d %d %d %d\n", dwY, dhY, dwC, dhC)
	if dwC != compInfo[Cr].downsampled_width || dhC != compInfo[Cr].downsampled_height {
		return nil, errors.New("Unsupported color subsampling (Cb and Cr differ)")
	}

	// Since the decisions about which DCT size and subsampling mode
	// to use, if any, are complex, instead just check the calculated
	// output plane sizes and infer the subsampling mode from that.
	var subsampleRatio image.YCbCrSubsampleRatio
	colorVDiv := 1
	switch {
	case dwY == dwC && dhY == dhC:
		subsampleRatio = image.YCbCrSubsampleRatio444
	case dwY == dwC && (dhY+1)/2 == dhC:
		subsampleRatio = image.YCbCrSubsampleRatio440
		colorVDiv = 2
	case (dwY+1)/2 == dwC && dhY == dhC:
		subsampleRatio = image.YCbCrSubsampleRatio422
	case (dwY+1)/2 == dwC && (dhY+1)/2 == dhC:
		subsampleRatio = image.YCbCrSubsampleRatio420
		colorVDiv = 2
	default:
		return nil, errors.New("Unsupported color subsampling")
	}

	// Allocate distination iamge
	dest = NewYCbCrAligned(image.Rect(0, 0, int(dinfo.output_width), int(dinfo.output_height)), subsampleRatio)

	var iMCURows int
	for i := 0; i < int(dinfo.num_components); i++ {
		compRows := int(C.DCT_v_scaled_size(dinfo, C.int(i)) * compInfo[i].v_samp_factor)
		if compRows > iMCURows {
			iMCURows = compRows
		}
	}
	//fmt.Printf("iMCU_rows: %d (div: %d)\n", iMCURows, colorVDiv)

	C.decode_ycbcr(dinfo,
		C.JSAMPROW(unsafe.Pointer(&dest.Y[0])),
		C.JSAMPROW(unsafe.Pointer(&dest.Cb[0])),
		C.JSAMPROW(unsafe.Pointer(&dest.Cr[0])),
		C.int(dest.YStride),
		C.int(dest.CStride),
		C.int(colorVDiv),
		C.int(iMCURows),
	)

	C.jpeg_finish_decompress(dinfo)
	return
}