Class: Oil::JPEGReader

Inherits:
Object
  • Object
show all
Defined in:
ext/oil/jpeg.c,
ext/oil/jpeg.c

Overview

Read a compressed JPEG image given an IO object.

Instance Method Summary collapse

Constructor Details

#new(io_in[, markers]) ⇒ Object

Creates a new JPEG Reader. io_in must be an IO-like object that responds to read(size).

markers should be an array of valid JPEG header marker symbols. Valid symbols are :APP0 through :APP15 and :COM.

If performance is important, you can avoid reading any header markers by supplying an empty array, [].

When markers are not specified, we read all known JPEG markers.

io = File.open("image.jpg", "r")
reader = Oil::JPEGReader.new(io)

io = File.open("image.jpg", "r")
reader = Oil::JPEGReader.new(io, [:APP1, :APP2])


289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'ext/oil/jpeg.c', line 289

static VALUE initialize(int argc, VALUE *argv, VALUE self)
{
	struct readerdata *reader;
	VALUE io, markers;
	struct jpeg_decompress_struct *dinfo;
	int i, marker_code;

	Data_Get_Struct(self, struct readerdata, reader);
	dinfo = &reader->dinfo;

	/* If source_io has already been set, then this is a re-used jpeg reader
	 * object. This means we need to abort the previous decompress to
	 * prevent memory leaks.
	 */
	if (reader->source_io) {
		jpeg_abort_decompress(dinfo);
	} else {
		jpeg_create_decompress(dinfo);
	}

	dinfo->src = &reader->mgr;

	rb_scan_args(argc, argv, "11", &io, &markers);
	reader->source_io = io;
	reader->mgr.bytes_in_buffer = 0;

	if(!NIL_P(markers)) {
		Check_Type(markers, T_ARRAY);
		for (i=0; i<RARRAY_LEN(markers); i++) {
			if (!SYMBOL_P(RARRAY_PTR(markers)[i])) {
				rb_raise(rb_eTypeError, "Marker code is not a symbol.");
			}
			marker_code = sym_to_marker_code(RARRAY_PTR(markers)[i]);
			jpeg_save_markers(dinfo, marker_code, 0xFFFF);
		}
	}

	/* Be warned that this can raise a ruby exception and longjmp away. */
	jpeg_read_header(dinfo, TRUE);

	jpeg_calc_output_dimensions(dinfo);

	return self;
}

Instance Method Details

#each(opts, &block) ⇒ self

Yields a series of binary strings that make up the output JPEG image.

Options is a hash which may have the following symbols:

:quality - JPEG quality setting. Betweein 0 and 100. :markers - Custom markers to include in the output JPEG. Must be a hash where

the keys are :APP[0-15] or :COM and the values are arrays of strings that
will be inserted into the markers.

Returns:

  • (self)


831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
# File 'ext/oil/jpeg.c', line 831

static VALUE each(int argc, VALUE *argv, VALUE self)
{
	struct readerdata *reader;
	struct writerdata writer;
	int state, width_out, ret;
	struct write_jpeg_args args;
	unsigned char *outwidthbuf;
	VALUE opts;

	rb_scan_args(argc, argv, "01", &opts);

	Data_Get_Struct(self, struct readerdata, reader);

	if (!reader->scale_width) {
		reader->scale_width = reader->dinfo.output_width;
	}
	if (!reader->scale_height) {
		reader->scale_height = reader->dinfo.output_height;
	}

	writer.cinfo.err = &reader->jerr;
	jpeg_create_compress(&writer.cinfo);

	width_out = reader->scale_width;
	ret = oil_libjpeg_init(&args.ol, &reader->dinfo, width_out,
		reader->scale_height);
	if (ret!=0) {
		jpeg_destroy_compress(&writer.cinfo);
		rb_raise(rb_eRuntimeError, "Unable to allocate memory.");
	}
	outwidthbuf = malloc(width_out * OIL_CMP(args.ol.os.cs));
	if (!outwidthbuf) {
		oil_libjpeg_free(&args.ol);
		jpeg_destroy_compress(&writer.cinfo);
		rb_raise(rb_eRuntimeError, "Unable to allocate memory.");
	}

	args.reader = reader;
	args.opts = opts;
	args.writer = &writer;
	args.outwidthbuf = outwidthbuf;
	reader->locked = 1;
	rb_protect((VALUE(*)(VALUE))each2, (VALUE)&args, &state);

	oil_libjpeg_free(&args.ol);
	free(outwidthbuf);
	jpeg_destroy_compress(&writer.cinfo);

	if (state) {
		rb_jump_tag(state);
	}

	return self;
}

#image_heightNumeric

The height of the image as indicated by the header.

This may differ from the height of the image that will be returned by the decompressor if we request DCT scaling.

Returns:

  • (Numeric)


476
477
478
479
480
481
# File 'ext/oil/jpeg.c', line 476

static VALUE image_height(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->image_height);
}

#image_widthNumeric

The width of the of the image as indicated by the header.

This may differ from the width of the image that will be returned by the decompressor if we request DCT scaling.

Returns:

  • (Numeric)


459
460
461
462
463
464
# File 'ext/oil/jpeg.c', line 459

static VALUE image_width(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->image_width);
}

#jpeg_color_spaceObject

Returns a symbol representing the color model in which the JPEG is stored, as indicated by the image header.

Possible color models are: :GRAYSCALE, :RGB, :YCbCr, :CMYK, and :YCCK. This method will return :UNKNOWN if the color model is not recognized.

This may differ from the color space that will be returned by the decompressor if we ask for a color space transformation.



400
401
402
403
404
405
406
407
408
409
# File 'ext/oil/jpeg.c', line 400

static VALUE jpeg_color_space(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	ID id;

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	id = j_color_space_to_id(dinfo->jpeg_color_space);

	return ID2SYM(id);
}

#markersHash

Get a hash of raw marker data from the JPEG.

The keys in the hash are the marker codes as symbols. The values are arrays.

Arrays since there may be multiple instances of a single marker in a JPEG marker.

Returns:

  • (Hash)


523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'ext/oil/jpeg.c', line 523

static VALUE markers(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	jpeg_saved_marker_ptr marker;
	VALUE hash, ary, key, val;

	hash = rb_hash_new();

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);

	for (marker=dinfo->marker_list; marker; marker=marker->next) {
		key = marker_code_to_sym(marker->marker);
		ary = rb_hash_aref(hash, key);
		if (NIL_P(ary)) {
			ary = rb_ary_new();
			rb_hash_aset(hash, key, ary);
		}
		val = rb_str_new((char *)marker->data, marker->data_length);
		rb_ary_push(ary, val);
	}

	return hash;
}

#num_componentsNumeric

Retrieve the number of components per pixel as indicated by the image header.

This may differ from the number of components that will be returned by the decompressor if we ask for a color space transformation.

Returns:

  • (Numeric)


345
346
347
348
349
350
# File 'ext/oil/jpeg.c', line 345

static VALUE num_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->num_components);
}

#out_color_componentsNumeric

Retrieve the number of components in the output color space.

Some color spaces have padding, so this may not accurately represent the size of output pixels.

Returns:

  • (Numeric)


379
380
381
382
383
384
# File 'ext/oil/jpeg.c', line 379

static VALUE out_color_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->out_color_components);
}

#out_color_spaceObject

Returns a symbol representing the color model to which the image will be converted on decompress.



419
420
421
422
423
424
425
426
427
428
# File 'ext/oil/jpeg.c', line 419

static VALUE out_color_space(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	ID id;

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	id = j_color_space_to_id(dinfo->out_color_space);

	return ID2SYM(id);
}

#out_color_space=(symbol) ⇒ Object

Set the color model to which the image will be converted on decompress.



437
438
439
440
441
442
443
444
445
446
447
# File 'ext/oil/jpeg.c', line 437

static VALUE set_out_color_space(VALUE self, VALUE cs)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.out_color_space = sym_to_j_color_space(cs);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return cs;
}

#output_componentsNumeric

Retrieve the number of bytes per pixel that will be in the output image.

Not all bytes will necessarily have data, since some color spaces have padding.

Returns:

  • (Numeric)


362
363
364
365
366
367
# File 'ext/oil/jpeg.c', line 362

static VALUE output_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_components);
}

#image_heightNumeric

The height of the image that will be output by the decompressor.

Returns:

  • (Numeric)


504
505
506
507
508
509
# File 'ext/oil/jpeg.c', line 504

static VALUE output_height(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_height);
}

#output_widthNumeric

The width of the of the image that will be output by the decompressor.

Returns:

  • (Numeric)


490
491
492
493
494
495
# File 'ext/oil/jpeg.c', line 490

static VALUE output_width(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_width);
}

#scale_denomNumeric

Retrieve the denominator of the fraction by which the JPEG will be scaled as it is read. This is 1, 2, 4, or 8 for libjpeg version 6b. In version 8b this is always the source DCT size, which is 8 for baseline JPEG.

Returns:

  • (Numeric)


593
594
595
596
597
598
# File 'ext/oil/jpeg.c', line 593

static VALUE scale_denom(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->scale_denom);
}

#scale_denom=(number) ⇒ Object

Set the denominator of the fraction by which the JPEG will be scaled as it is read. This can be set to 1, 2, 4, or 8 for libjpeg version 6b. In version 8b this must always be the source DCT size, which is 8 for baseline JPEG.

Prior to version 1.2, libjpeg-turbo will not scale down images on decompression, and this option will do nothing.



612
613
614
615
616
617
618
619
620
621
622
# File 'ext/oil/jpeg.c', line 612

static VALUE set_scale_denom(VALUE self, VALUE scale_denom)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.scale_denom = NUM2INT(scale_denom);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return scale_denom;
}

#scale_heightNumeric

Retrieve the height to which the image will be resized after decompression. A height of 0 means the image will remain at original height.

Returns:

  • (Numeric)


664
665
666
667
668
669
# File 'ext/oil/jpeg.c', line 664

static VALUE scale_height(VALUE self)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	return INT2FIX(reader->scale_height);
}

#scale_height=(number) ⇒ Object

Set the height to which the image will be resized after decompression. A height of 0 means the image will remain at original height.



679
680
681
682
683
684
685
686
# File 'ext/oil/jpeg.c', line 679

static VALUE set_scale_height(VALUE self, VALUE scale_height)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);
	reader->scale_height = NUM2INT(scale_height);
	return scale_height;
}

#scale_numNumeric

Retrieve the numerator of the fraction by which the JPEG will be scaled as it is read. This is always 1 for libjpeg version 6b. In version 8b this can be 1 to 16.

Returns:

  • (Numeric)


556
557
558
559
560
561
# File 'ext/oil/jpeg.c', line 556

static VALUE scale_num(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->scale_num);
}

#scale_num=(number) ⇒ Object

Set the numerator of the fraction by which the JPEG will be scaled as it is read. This must always be 1 for libjpeg version 6b. In version 8b this can be set to 1 through 16.



572
573
574
575
576
577
578
579
580
581
582
# File 'ext/oil/jpeg.c', line 572

static VALUE set_scale_num(VALUE self, VALUE scale_num)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.scale_num = NUM2INT(scale_num);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return scale_num;
}

#scale_widthNumeric

Retrieve the width to which the image will be resized after decompression. A width of 0 means the image will remain at original width.

Returns:

  • (Numeric)


632
633
634
635
636
637
# File 'ext/oil/jpeg.c', line 632

static VALUE scale_width(VALUE self)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	return INT2FIX(reader->scale_width);
}

#scale_width=(number) ⇒ Object

Set the width to which the image will be resized after decompression. A width of 0 means the image will remain at original width.



647
648
649
650
651
652
653
654
# File 'ext/oil/jpeg.c', line 647

static VALUE set_scale_width(VALUE self, VALUE scale_width)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);
	reader->scale_width = NUM2INT(scale_width);
	return scale_width;
}